Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
proposal-symbol-proto — TC39 proposal for mitigating prototype pollution | Kitploit
도구/GitHubGitHub/tc39/proposal-symbol-proto
Vulnerability AnalysisWeb SecurityPapers & ResearchLearning & Education
GitHubtc39/proposal-symbol-proto

proposal-symbol-proto

TC39 proposal for mitigating prototype pollution

저장소 보기
5322년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

프로토타입 오염 완화 / Symbol.proto

작성자: Santiago Díaz (Google)

챔피언: Shu-yu Guo (Google)

단계: 1

목차

  • 문제 설명
    • 유령 같은 원격 작용
    • 데이터 전용 공격
  • freeze, seal, preventExtensions의 문제점
    • 오버라이드 실수
    • 거친 세분성
    • 동결 시점
    • 애플리케이션 유형
  • 제안 해결책
    • 리플렉션 API 제공
    • 옵트인 기능
      • 자동 리팩터링
    • 삭제란 무엇을 의미하는가?
  • 호환되지 않는 코드베이스
  • 부록
    • constructor 오염은 어떨까?
    • 축소된 JS에서의 계산된 접근
    • 취약점 예시

tl;dr

이 제안은 freeze 프리미티브를 보완하는 메커니즘과 대부분의 코드베이스를 이에 호환되게 만드는 메커니즘을 통해 프로토타입 오염(prototype pollution)으로 알려진 언어 수준의 취약점을 완화하려고 합니다. 프로토타입이 리플렉션 API를 통해서만 접근 가능하도록 하는 옵트인 기능을 설명합니다. 이를 통해 obj[key] 문은 더 이상 프로토타입에 접근할 수 없습니다. 이 기능과 호환되는 코드베이스는 프로토타입을 사용하는 방식에 있어 더 _의도적_입니다.

문제 설명

유령 같은 원격 작용

PP 취약점은 공격자가 런타임에 제어하지 않거나 접근할 수 없는 객체를 조작할 수 있게 합니다. 이 '유령 같은 원격 작용' 프리미티브는 다른 객체의 형태를 바꾸고 속성을 재정의하는 데 사용될 수 있으며, 이를 통해 런타임의 객체를 오염시킵니다.

오염된 객체는 그렇지 않았다면 안전/정확했을 코드의 기본 가정을 무효화하고, JS 코드베이스에서 임의 코드 실행과 광범위한 기타 보안 문제를 초래할 수 있습니다. 프로토타입 오염 버그는 웹 애플리케이션에서 자주 나타나지만, 웹이 아닌 JS 런타임에도 영향을 미칩니다.

JS에서 객체 속성은 해당 속성을 참조할 수 있는 모든 코드가 쓸 수 있습니다. 특히 많은 객체가 공유 속성에 의존하는 경우, 그중 하나가 다른 모든 객체에 변경을 가할 수 있습니다.

데이터 전용 공격

PP의 특별한 속성은 데이터 전용 공격이라는 점입니다. 즉 순수하게 데이터만으로 코드 실행을 달성할 수 있습니다. 예를 들어 다음의 취약한 코드와 그에 대응하는 익스플로잇을 보십시오.

root@kitploit:~
// source is attacker-controlled
function merge(target, source) {
  for (let key in source) {
    if (typeof source[key] === 'object')  {
      if(target[key] === undefined) {
        target[key] = {};
      }
      target[key] = merge(target[key], source[key]);
    } else {
      target[key] = source[key];
    }
  }
  return target;
}

// User input comes as a string
const userSuppliedObj = JSON.parse('{"__proto__": {"polluted": true}}');
// Trigger prototype pollution
merge({}, userSuppliedObj);
// Create a brand new object
const newObj = {};
// Has polluted property
console.log(newObj.polluted); // true

익스플로잇은 외부 코드를 주입하지 않고도 새 객체의 생성을 오염시킬 수 있다는 점에 유의하세요.

이 특별한 속성 때문에 Content Security Policy나 Trusted Types 같은 코드 실행 문제에 대한 현대적 완화 조치는 PP를 보호하는 데 한계가 있습니다. 이들은 코드 출처 적용에 초점을 맞추기 때문입니다.

참고 데이터 전용 공격은 VM에서 실행 중인 코드를 신뢰하고 임의 코드 실행이 보안 영향이 있는 상황과 관련이 있습니다.

freeze, seal, preventExtensions의 문제점

기존 동결 프리미티브는 널리 채택되기 어렵게 만드는 상당한 설계 문제가 있습니다. 전문 사용자에게는 유용할 수 있지만, 프로토타입이 변경 가능하리라고 합리적으로 기대하는 대부분의 개발자가 사용하기에는 적합하지 않습니다:

오버라이드 실수

Freeze API는 오버라이드 실수와 기타 불일치로 인해 기존 코드베이스에 버그를 유발하며, 예외를 던지거나 더 나쁘게는 슬로피 모드에서 조용히 실패 합니다. 오버라이드 실수에 대한 이전 조사에서는 엄격 모드의 약 10% 코드베이스와 슬로피 모드의 20%에서 오버라이드 실수가 발생한다고 결론지었습니다. 그 조사는 곧 중단되었습니다.

거친 세분성

Freeze API는 개발자가 보안 코드베이스를 유지하기 위해 어떤 프로토타입을 동결해야 하는지 알아야 하는 무거운 책임을 부여합니다. 즉 개발자가 보안 전문가라고 가정합니다. 이 API는 보안의 무엇(what) 만 설명할 뿐 어떻게(how) 는 설명하지 않습니다. Object를 동결하는 것만으로는 충분하지 않습니다. 많은 익스플로잇이 Array를 악용하기 때문입니다. Error, Date, Reflect, Proxy는 어떻습니까? 아니면 향후 내장 타입은요? Freeze API는 이러한 질문에 답하지 못합니다.

동결 시점

Freeze API는 안정적인 동결 시점, 즉 런타임에서 프로토타입이 확정되어 동결될 수 있는 고정된 순간을 가정합니다. 실제로 이 시점은 변동적이며 활발히 개발되는 코드베이스에서 시간이 지남에 따라 바뀝니다. 오늘날 많은 애플리케이션에서 그러한 시점을 찾을 수 있지만, 새 종속성, 폴리필, 코드 구조 변경, 핫스와핑 및 개발자 도구 같은 고급 기능이 추가되면서 동결 시점은 움직이는 표적이 됩니다.

애플리케이션 유형

Freeze API는 전체 프로토타입 체인을 보호할 수 없습니다. JS에서는 객체가 언제든지 프로토타입 체인에 추가되거나 제거될 수 있습니다. 전체 체인을 보호하려면 체인에 추가되는 객체를 항상 동결해야 하며, 이는 오류가 발생하기 쉬운 과정입니다. 체인에서 제거된 객체는 다시 동결을 해제할 수 없습니다.

제안 해결책

한마디로: 프로토타입을 리플렉션 API에만 노출하는 기능입니다. 프로토타입이 __proto__나 prototype 같은 속성을 통해 제공되지 않는다면 데이터 전용 문제에 노출되지 않을 것입니다.

이것은 예시를 통해 더 잘 이해할 수 있습니다. obj[one][two] = value 문은 obj.__proto__.polluted를 통해 PP에 취약합니다. Object.prototype.__proto__ 속성을 삭제하면 같은 문은 더 이상 취약하지 않습니다. 프로토타입에 도달하는 유일한 다른 경로인 obj.constructor.prototype.polluted에 맞지 않기 때문입니다. 프로토타입은 삭제할 수 없다는 점에 유의하세요.

이 제안은 리플렉션 API를 제공하고 프로토타입 속성을 삭제하는 새로운 옵트인 캡슐화 기능을 만드는 방식으로 구현할 수 있습니다. 각 단계에 대한 설명은 다음과 같습니다.

리플렉션 API 제공

__proto__는 삭제할 수 있는 레거시 속성 이름이지만, 그 뒤에 있는 내부 슬롯은 여전히 Object/Reflect.getPrototypeOf로 읽고 Object/Reflect.setPrototypeOf로 쓸 수 있습니다. 따라서 이미 실행 중인 코드는 이 속성에 계속 접근할 수 있습니다.

우리는 prototype을 위한 새 API, 예를 들어 getClassPrototypeOf와 setClassPrototypeOf의 생성을 제안합니다. 이렇게 하면 이 특수 속성의 작동 방식이나 VM을 지원하는 방식을 전혀 바꾸지 않으면서 이 속성 이름을 삭제할 수 있습니다.

리플렉션 API는 폴리필될 수 있으므로 강화된 코드베이스가 구형 버전을 포함한 모든 브라우저에서 작동할 수 있습니다.

옵트인 기능

프로토타입 슬롯의 getter 및 setter 함수에 대해 속성 이름이 생성되지 않는 새로운 옵트인 '캡슐화 기능'입니다. 이제 해당 속성에 대한 참조가 대신 리플렉션 API를 사용할 수 있기 때문에 가능합니다.

이 기능은 대역 외 플래그를 통해 활성화됩니다.

  • 브라우저 컨텍스트에서는 X-Encapsulate-Prototype: true 같은 HTTP 헤더를 통해
  • 기타 컨텍스트에서는 --encapsulate-prototype 같은 기능 플래그를 통해

캡슐화가 비활성화 되면 프로토타입은 속성과 리플렉션 API를 통해 모두 접근할 수 있습니다.

캡슐화가 활성화 되면 __proto__와 prototype이 모두 삭제되어 프로토타입은 리플렉션 API를 통해서만 접근할 수 있습니다.

캡슐화에는 다음과 같은 자동 리팩터링 기능도 포함됩니다:

자동 리팩터링

캡슐화가 활성화되면 JS 엔진은 새 소스 코드를 로드할 때 파싱 단계에 추가 단계를 활성화하여 프로토타입 속성에 대한 모든 점 표기법을 마치 리플렉션 API 호출인 것처럼 등록합니다. 이 단계는 효율적으로 구현될 수 있으며 타사, 전이적 또는 동적으로 로드된 종속성이 있는 코드베이스가 캡슐화와 호환될 수 있게 합니다.

향후 이 변경은 prototype을 더 이상 사용되지 않는 것으로 표시하는 길을 열 것입니다.

삭제란 무엇을 의미하는가?

캡슐화가 활성화되면 프로토타입 속성은 단순히 undefined가 될 수 있지만, 읽기/쓰기를 시도할 때 오류를 던질 수도 있습니다. 이는 더 빠르고 분명하게 실패하는 것을 의미하며, 리플렉션 API/캡슐화로의 마이그레이션을 테스트할 수 있게 합니다.

이는 eval 함수가 Content Security Policy 아래에서 예외를 던지는 것과 같은 방식으로 호스트 훅을 사용하여 __proto__와 prototype의 getter와 setter를 캡슐화 여부에 따라 조건부로 만든다는 것을 의미합니다.

호환되지 않는 코드베이스

프로토타입을 참조하기 위해 _계산된 속성 접근_에 의존하는 코드는 캡슐화나 자동 리팩터링과 호환되지 않습니다. 프로토타입을 사용할 때 명시적으로 참조하도록 리팩터링해야 합니다. 이 리팩터링은 실제로 코드가 의도를 표현하게 만들어 정적 분석에 위험한 패턴이 드러나게 합니다. 실제로 이러한 특성을 가진 코드베이스는 대개 리플렉션 프레임워크, 디버깅 도구, 그리고 프로토타입을 어떻게 사용하는지 잘 알고 있을 가능성이 높은 리플렉션 중심 사용 사례입니다.

prototype이라는 단어를 사용자 정의 속성을 정의하는 데 사용하는 코드베이스는 호환되지 않습니다. 이러한 코드베이스는 이 속성이 항상 대괄호 표기법을 통해 설정/조회된다면 캡슐화와 호환되도록 만들 수 있습니다. 역사적으로, 그리고 HTTP Archive 쿼리에 따르면 이 이유로 호환되지 않는 코드베이스는 작은 비율입니다.

부록

constructor 오염은 어떨까?

constructor 속성에 대한 일부 변경도 유령 같은 원격 작용을 일으킬 수 있습니다. 연구 중에는 이에 영향을 받는 실질적인 취약점을 발견하지 못했습니다.

이 공격이 성공하기 위한 기준은 상당히 높습니다. PP와 마찬가지로 임의 속성을 쓰고 그리고 읽을 수 있는 가젯을 가진 애플리케이션을 찾아야 합니다. 그러나 constructor 오염에서 읽기 가젯은 polluted 대신 constructor.polluted에서 읽어야 합니다. 이는 유용한 가젯의 수를 극적으로 줄입니다.

축소된 JS에서의 계산된 접근

일부 축소된 JS는 정적 속성 접근이 계산된 접근으로 축소될 수 있기 때문에 캡슐화 모드와 호환되지 않을 수 있습니다. 우리는 HTTP Archive를 조회하여 실제로 이를 추정했습니다. 다음 표는 이 동작을 보이는 페이지가 데스크톱 브라우저로 크롤링된 모든 페이지 중 지난 12개월 동안 일관되게 1% 미만임을 보여줍니다.

취약점 예시

Google은 취약점 보상 프로그램에 제출된 버그의 증가 추세를 확인했습니다. 2020년 1건, 2021년 3건, 2022년 현재까지 5건입니다. 내부 연구에서도 몇 가지를 더 식별했습니다.

취약점 예시는 다음과 같습니다.

  1. 웹: Strict CSP를 사용하므로 보호되어야 했던 서비스의 여러 XSS 문제. 그리고 다양한 알려진 취약 라이브러리.
  2. 데스크톱: Google 소유 데스크톱 애플리케이션의 버그로, 사용자에게 악성 JSON 객체가 제공되어 오염 취약점으로 인해 로컬 파일이 유출될 수 있었습니다. (현재 비공개, 공개 시점 미정.)
  3. 보안 기능: Chrome의 Sanitizer API, DOMPurify 및 Closure sanitizer를 포함한 새니타이저의 여러 우회.
  4. 브라우저: 원격 코드 실행으로 이어지는 Firefox 샌드박스 탈출.
  5. NodeJS: 여러 RCE가 발견되었습니다.

JavaScript 애플리케이션이 더 많은 환경(예: Electron, Cloudflare Workers 등)에 배포됨에 따라 취약한 애플리케이션의 수가 증가할 것으로 예상합니다. 따라서 모든 환경에서 공격을 완화하려면 언어 수준의 해결책이 필요합니다.

도구 다운로드
Table__proto__ 또는 constructor에 동적으로 접근하는 문서크롤링된 전체 문서 수비율
2023_03_01_desktop5,407,936609,469,4580.89%
2023_02_01_desktop4,842,383549,089,7080.88%
2023_01_01_desktop5,283,826589,519,1600.90%
2022_12_01_desktop5,161,471577,073,8830.89%
2022_11_01_desktop5,023,169561,726,2390.89%
2022_10_01_desktop4,393,377476,880,6240.92%
2022_09_01_desktop4,239,257466,278,7620.91%
2022_08_01_desktop4,259,814463,784,0470.92%
2022_07_01_desktop3,011,137339,468,6150.89%
2022_06_01_desktop2,301,317257,501,2220.89%
2022_04_01_desktop2,368,577263,144,6570.90%
2022_03_01_desktop2,319,518259,249,0130.89%