HANGUL.WIKI

웹 애플리케이션 보안과 프로토타입 오염 취약점

Web Application Security: Prototype Pollution and Jailbreak Vulnerabilities

금융·건강·법률 등 민감 주제입니다. 중요한 결정 전 전문가 확인을 권장합니다. 고지·면책 안내
2026-09-06
목차 (7개 섹션)

2018년 11월, npm 패키지 매니저 생태계에 조용한 파장이 일었다. 보안 연구자들이 lodash와 jQuery를 비롯한 인기 라이브러리 수십 개에서 동일한 계열의 결함을 잇달아 찾아냈기 때문이다. 이름하여 "프로토타입 오염(Prototype Pollution)". 겉보기엔 사소한 객체 병합 버그처럼 보였지만, 실제로는 자바스크립트 언어 설계 그 자체의 특성을 파고든 취약점이었다.

자바스크립트의 모든 객체는 Object.prototype이라는 공용 원형을 상속받는다. {}로 새 객체를 만들어도, 그 객체는 보이지 않는 실에 묶여 Object.prototype과 연결돼 있다. 문제는 __proto__라는 특수 키를 통해 이 원형에 직접 접근할 수 있다는 데 있다. 공격자가 사용자 입력값을 재귀적으로 병합하는 함수(merge, extend, clone 등)에 {"__proto__": {"isAdmin": true}} 같은 JSON을 밀어넣으면, 병합 로직이 이를 그대로 처리하면서 전역 원형 객체에 isAdmin 속성을 심어버린다. 그 순간부터 애플리케이션 내 모든 객체는 별도의 선언 없이도 isAdmin: true를 상속받게 된다.

파급력은 여기서 끝나지 않는다. 2019년 카네기멜론대 CERT/CC와 스노크(Snyk)가 공동 발표한 분석에 따르면, 단순 권한 상승을 넘어 서비스 거부(DoS), 심하게는 원격 코드 실행(RCE)으로까지 이어질 수 있었다. 특히 Node.js 서버 환경에서 child_process나 템플릿 엔진(예: 오래된 버전의 handlebars, pug)과 결합될 경우, 오염된 원형 속성이 명령어 실행 경로에 개입해 임의 코드가 실행되는 사례가 실제 CVE로 다수 등록됐다. lodash는 CVE-2018-3721, CVE-2019-10744 두 차례에 걸쳐 이 문제로 패치를 냈고, 당시 주간 다운로드 2천만 건이 넘는 패키지였던 만큼 영향 범위는 사실상 전체 npm 생태계에 가까웠다.

방어책을 두고도 개발자 커뮤니티 내에서 논쟁이 있었다. 일각에서는 Object.freeze(Object.prototype)로 원형 자체를 동결하는 방법을 제시했지만, 이는 프레임워크 내부 동작을 깨뜨리는 부작용이 보고되며 실무 도입이 제한적이었다. 결국 업계 표준으로 자리잡은 대응은 Object.create(null)로 원형이 없는 객체를 만들거나, Map 자료구조로 사용자 입력을 다루는 방식, 그리고 병합 함수 내부에서 __proto__, constructor, prototype 키를 명시적으로 차단하는 방식이다. OWASP는 2021년판 Top 10 개정 논의에서 이 취약점을 "인젝션" 범주의 하위 사례로 편입하는 안을 검토하기도 했다. 정적 분석 도구만으로는 탐지가 까다로워, 실전에서는 코드 리뷰와 의존성 스캔(예: npm audit, Snyk)을 병행하는 것이 일반적인 관행으로 굳어졌다.

취약점 작동 기전과 세부 단계

프로토타입 오염은 자바스크립트의 공용 원형 상속 구조를 조작하는 취약점이다. 이 취약점은 사용자 입력을 처리하는 라이브러리 및 애플리케이션의 객체 병합 과정에서 발생한다.

작동 원리는 입력, 처리, 결과의 단계적 순서로 진행된다.

  • 입력 단계: 공격자가 __proto__ 키를 포함한 JSON 데이터를 대상 애플리케이션에 전달한다.
  • 처리 단계: merge, extend, clone 등의 재귀 병합 함수가 입력값을 검증 없이 복사하면서 전역 Object.prototype 객체에 접근한다.
  • 결과 단계: 전역 원형 객체에 새로운 속성이 등록되며, 애플리케이션 내의 모든 객체가 해당 속성을 상속받는다.
  • 이러한 속성 변조는 애플리케이션의 권한 검증이나 실행 경로에 영향을 미친다. 2019년 카네기멜론대 CERT/CC와 스노크의 분석에 따르면, 이 취약점은 권한 상승뿐만 아니라 서비스 거부(DoS)나 원격 코드 실행(RCE)으로 이어질 수 있는 것으로 알려졌다. 다만 원격 코드 실행은 Node.js 서버 환경에서 child_process 모듈이나 이전 버전의 handlebars, pug 같은 템플릿 엔진과 결합될 때 성립하는 것으로 나타났다.

    방어 기법의 원리와 한계

    프로토타입 오염에 대한 방어 기법은 객체 구조 변경, 자료구조 대체, 입력 키 차단 방식으로 나뉜다.

    첫째, Object.create(null)을 사용하는 방식이다. 이 방식은 Object.prototype을 상속받지 않는 객체를 생성하여 원형 오염 경로를 차단한다. 둘째, Map 자료구조를 사용하는 방식이다. 객체 대신 Map을 활용하여 사용자 입력을 관리함으로써 원형 속성의 변조를 방지하는 것으로 보인다. 셋째, 병합 함수 내부에서 __proto__, constructor, prototype 키를 명시적으로 차단하는 방식이다. 이 방식은 악의적인 키가 재귀 병합 로직에 전달되는 과정을 직접 차단한다.

    원형 동결 방식인 Object.freeze(Object.prototype)는 전역 원형의 수정을 차단하는 효과가 있다. 그러나 프레임워크 내부 동작을 깨뜨리는 부작용이 보고되어 실무 적용에는 한계가 있는 것으로 평가받는다.

    탐지 및 관리 체계

    프로토타입 오염은 정적 분석 도구만으로는 식별이 까다로운 특성이 있다. 따라서 실무에서는 코드 리뷰와 더불어 npm audit, Snyk과 같은 의존성 스캔 도구를 병행하는 방식이 일반적인 관행으로 굳어졌다.

    OWASP는 2021년판 Top 10 개정 논의 과정에서 이 취약점을 인젝션 범주의 하위 사례로 편입하는 방안을 검토한 것으로 알려졌다. lodash와 같은 주요 패키지에서는 CVE-2018-3721 및 CVE-2019-10744 패치를 적용하여 결함을 해결했다.

    주요 라이브러리 사례 및 생태계 파급 효과

    프로토타입 오염은 오픈소스 라이브러리와 패키지 생태계 전반에 걸쳐 광범위한 영향을 미치는 보안 결함이다. 이 취약점은 다수의 상위 의존성 패키지에 잠재하여 이를 참조하는 애플리케이션 전반으로 확산된다.

    원인과 변화 및 결과의 전개 과정은 다음과 같다.

  • 원인: 2018년 11월 lodash와 jQuery를 포함한 수십 개의 인기 라이브러리에서 재귀 객체 병합과 관련된 동일 계열의 결함이 식별되었다.
  • 변화: 라이브러리 내부의 병합 로직이 검증되지 않은 __proto__ 키를 처리하면서 Object.prototype에 임의 속성이 주입되었다.
  • 결과: 당시 주간 다운로드 2천만 건을 초과하던 lodash는 CVE-2018-3721 및 CVE-2019-10744로 두 차례 패치를 배포하였으며, 취약점의 파급 범위는 사실상 전체 npm 생태계에 도달한 것으로 평가받는다.
  • 취약점 악용에 따른 실행 환경별 파급 효과는 성립 조건에 따라 구별된다. 단순 권한 검증 우회는 전역 원형 속성의 변조만으로 발생할 수 있다. 반면 원격 코드 실행은 Node.js 서버 환경에서 child_process 모듈이나 handlebars 및 pug의 이전 버전 템플릿 엔진과 결합할 때 성립하는 것으로 분석된다. 서비스 거부(DoS) 역시 전역 객체 변조를 통해 유발될 수 있는 것으로 알려졌다.

    재귀 병합 함수의 단계별 처리 구조

    재귀 병합 함수는 다중 계층의 객체 데이터를 결합하고 복사하는 핵심 기능을 수행한다. 자바스크립트 애플리케이션에서는 merge, extend, clone 등의 함수가 사용자 입력을 객체로 구성하는 데 널리 활용된다.

    입력 데이터 처리와 속성 주입의 작동 순서는 다음과 같다.

  • 1단계 입력 수신: 애플리케이션이 외부 사용자로부터 __proto__ 키가 포함된 JSON 형태의 데이터를 전달받는다.
  • 2단계 객체 순회: 병합 함수가 입력 데이터의 키와 값을 순차적으로 탐색하며 대상 객체로의 재귀 복사를 수행한다.
  • 3단계 원형 접근: 복사 과정에서 __proto__ 키에 대한 검증이 결여된 경우 전역 Object.prototype 객체에 직접 접근한다.
  • 4단계 속성 할당: 지정된 속성이 Object.prototype에 등록되며, 애플리케이션 내의 모든 객체가 선언 없이 해당 속성을 상속받는 상태로 전환된다.
  • 이러한 단계적 오염을 방지하기 위해 함수 내부에서 __proto__, constructor, prototype 키를 명시적으로 검증하여 차단하는 기법이 적용된다. 이 방식은 악의적인 키가 순회 및 복사 로직으로 진입하는 경로를 직접 차단한다.

    대응 전략별 메커니즘과 적용 제약

    프로토타입 오염에 대한 보안 대응책은 객체 구조 변경, 자료구조 전환, 전역 원형 동결의 세 가지 형태로 구분된다. 각 전략은 취약점 발생 지점을 격리하거나 수정 권한을 제어하는 방식으로 동작한다.

    대응 전략별 세부 작동 메커니즘은 다음과 같다.

  • Object.create(null) 방식: Object.prototype을 상속받지 않는 원형 없는 객체를 생성한다. 원형 상속 연결이 존재하지 않으므로 외부 입력이 원형 객체로 전파되는 경로가 원천 차단된다.
  • Map 자료구조 활용 방식: 사용자 입력을 일반 객체 대신 Map 구조로 관리한다. 속성 상속 체계와 분리된 키-값 저장 방식을 사용하여 원형 변조를 방지하는 것으로 보인다.
  • Object.freeze(Object.prototype) 방식: 전역 Object.prototype을 동결 상태로 지정한다. 전역 원형 객체의 모든 속성 추가 및 수정을 차단하는 효과를 낸다.
  • 각 대응 전략의 도입에는 다음과 같은 기술적 제약과 한계가 수반된다. Object.freeze(Object.prototype) 방식은 원형 변조를 차단할 수 있으나 프레임워크 내부 동작을 깨뜨리는 부작용이 발생하여 실무 도입이 제한적인 것으로 평가받는다. 이에 따라 실무 환경에서는 Object.create(null)을 통한 원형 배제, Map 자료구조 적용, 병합 함수 내 위험 키 차단 방식이 표준 대응으로 채택되었다.

    검증 체계 및 보안 분류 표준

    보안 검증 체계는 소프트웨어 개발 및 배포 과정에서 잠재적 결함을 식별하기 위해 운영된다. 프로토타입 오염은 정적 분석 도구만으로는 탐지하기 까다로운 한계가 존재한다.

    실무적 검증 체계의 구성은 다음과 같다.

  • 코드 리뷰: 병합 함수의 구현 방식과 입력 데이터에 대한 키 검증 로직의 적용 여부를 수동으로 검토한다.
  • 의존성 스캔: npm audit 및 Snyk과 같은 자동화 도구를 병행하여 알려진 취약 패키지의 포함 여부를 추적한다.

국제 보안 표준 기구의 분류 논의에서도 해당 결함이 검토되었다. OWASP는 2021년판 Top 10 개정 논의 과정에서 프로토타입 오염을 인젝션 범주의 하위 사례로 편입하는 방안을 검토한 것으로 알려졌다. lodash를 비롯한 주요 패키지는 CVE-2018-3721 및 CVE-2019-10744 패치를 통해 결함을 수정함으로써 생태계 내 위험을 완화했다.

관련 문서

문서 정보

최초 작성
최종 갱신
분류
기술

HANGUL.WIKI가 정리·작성한 문서입니다. 정확성을 위해 노력하나 오류가 있을 수 있으므로, 중요한 내용은 공식 출처를 통해 확인하시기 바랍니다. 내용의 오류나 정정 요청은 오류·정정 신고로 알려주시면 검토 후 반영합니다.