원격 프로퍼티 주입 (Prototype Pollution)
Remote Property Injection
설명
원격 프로퍼티 주입은 신뢰할 수 없는 입력값을 객체의 키(프로퍼티 이름)나 HTTP 헤더 이름으로 사용하여 동적으로 대입할 때 발생합니다. 공격자는 "proto", "prototype", "constructor" 같은 핵심 프로퍼티를 덮어써 전체 애플리케이션의 동작을 오염시키는 Prototype Pollution을 유발하거나, 사용자 입력으로 헤더 이름을 조작해 Content-Security-Policy, Access-Control-Allow-Origin 등의 중요한 보안 헤더를 임의로 변경할 수 있습니다. 예: 쿼리 파라미터로 proto[polluted]=true 를 전달하여 모든 객체에 예기치 않은 프로퍼티가 생기게 하거나, 요청 파라미터로 헤더 이름을 전달해 CSP를 비활성화하도록 조작하는 방식으로 악용될 수 있습니다.
잠재적 영향
프로토타입 오염(Prototype Pollution): 전역 객체 동작 변경, 우회, 예외 유발 등 시스템 전반의 예기치 않은 동작 발생
보안 헤더 덮어쓰기: CSP, CORS 등 핵심 보안 헤더가 무력화되어 XSS, 데이터 유출 위험 증가
서비스 거부(DoS): 오염된 프로퍼티로 인한 런타임 예외, 무한 루프, 리소스 과다 소모로 서비스 중단
데이터 무결성 훼손: 애플리케이션 로직이 변질되어 데이터가 잘못 기록되거나 검증 단계가 우회됨
해결 방법
객체 대신 ES2015 Map 사용: 동적 키 저장이 필요하면 일반 객체(Object) 대신 Map을 사용하여 프로토타입 체인 오염을 원천 차단합니다.
키 접두어 적용: 부득이하게 객체 키에 사용자 입력을 쓸 경우, "$" 같은 고정 접두어를 붙여 내장 프로퍼티(proto, constructor 등)와 충돌을 피합니다.
허용 목록(Allowlist) 검증: 헤더 이름은 사용자 입력을 그대로 쓰지 말고, 필요한 특정 이름만 허용합니다. 값도 길이/문자셋 검증을 수행합니다.
안전한 기본 객체: 동적 키를 반드시 객체에 저장해야 한다면 Object.create(null)로 프로토타입이 없는 빈 객체를 사용합니다.
입력 검증/정규화: 키/헤더 이름에 대해 길이 제한과 안전한 문자 집합(예: [A-Za-z0-9_-])만 허용하고, 위험 키(proto, prototype, constructor)는 차단합니다.
취약한 코드 및 안전한 코드 예시
취약한 코드
안전한 코드
설명:
취약한 코드:
사용자 입력값을 객체 키로 그대로 사용하면 proto, prototype, constructor 같은 내부 프로퍼티가 덮어써져 전역적으로 예기치 않은 동작(Prototype Pollution)을 일으킬 수 있습니다.
사용자 입력을 헤더 이름으로 사용하면 공격자가 CSP, CORS 같은 중요 보안 헤더를 제거/변경하여 XSS나 데이터 유출로 이어질 수 있습니다.
안전한 코드:
Map을 사용해 동적 키를 저장하면 프로토타입 체인에 영향을 주지 않아 Prototype Pollution을 차단합니다.
불가피하게 객체를 쓸 때는 고정 접두어("$")를 붙여 내장 프로퍼티와 충돌하지 않도록 하며, 키에 대해 길이와 문자셋 검증으로 위험 키를 차단합니다.
헤더 이름은 허용 목록 기반으로만 설정하고 값에 대해서도 길이 등 검증을 수행하여 보안 헤더 덮어쓰기를 방지합니다.
참조
Last updated