해당 포스팅은 학습목적이며, PortSwigger의 web-security 를 기반으로 작성되었습니다.
▶https://portswigger.net/web-security/prototype-pollution/preventing
Preventing prototype pollution vulnerabilities
exploit 가능한 가젯과 결합되어 있는지 여부에 관계 없이 웹 사이트에서 발견된 프로토타입 오염 취약점은 모두 패치를 적용하는 것이 좋다. 취약점을 놓치지 않았다고 확신하더라도 향후 코드나 사용하는 라이브러리의 업데이트가 새로운 가젯을 도입하여 실행 가능한 익스플로잇의 가능성을 주지 않을 것이라는 보장은 없다.
( 그동안 prototype pollution Lab을 통해 학습한 기법에 대한 조치를 확인한다. )
Sanitizing property keys
prototype pollution 취약점을 방지하는 가장 확실한 방법 중 하나는 속성 키를 기존 객체에 병합하기 전에 살균하는 것이다.
이렇게 하면 공격자가 개체의 프로토타입을 참조하는 __proto__ 와 같은 키를 삽입하는 것을 방지할 수 있다.
허용된 키의 허용 목록(white list)을 사용하는 것이 가장 효과적인 방법이다. 그러나 대부분의 경우 이 방법이 불가능하므로 대신 차단 목록(black list)을 사용하여 사용자 입력에서 잠재적으로 위험한 문자열을 제거하는 것이 일반적이다.
이는 빠르게 구현할 수 있는 방법이고, __proto__를 성공적으로 차단했지만 공격자가 생성자를 통해 객체의 프로토타입을 오염시키는 것을 고려하지 못한 사이트는 진정으로 강력한 차단 목록을 확립했다고 보기 어렵고 실제로 그러한 차단 목록을 갖추는 것도 까다롭다. 또한 난독화 기술을 사용해 우회할 수도 있다. 이는 장기적인 해결 책이 아닌 임시적인 방편으로만 권장된다.
Preventing changes to prototype objects
prototype pollution 취약점을 방지하는 더 강력한 접근 방식은 prototype 객체를 아얘 변경하지 못하도록 하는 것이다. 객체에서 Object.freeze() 메서드를 호출하면 해당 프로퍼티와 그 값을 더 이상 수정할 수 없고 새 프로퍼티를 추가할 수 없다. 프로토타입은 객체 자체에 불과하므로 이 메서드를 사용하여 잠재적인 소스를 사전에 차단할 수 있다.
Object.freeze(Object.prototype);
Object.seal() 메서드도 비슷하지만 기존 프로퍼티의 값을 변경할 수 있다. ( 어떤 이유로든 Object.freeze()를 사용할 수 없는 경우 좋은 절충안이 될 것이다. )
Preventing an object from inheriting properies
Object.freeze()를 사용하여 잠재적인 프로토타입 오염 소스를 차단할 수 있지만, 가젯을 제거하는 조치를 취할 수도 있다. 이렇게 하면 공격자가 프로토타입 오염 취약점을 식별하더라도 이를 악용할 수 없을 가능성이 높다.
기본적으로 모든 Object는 프로토타입 체인을 통해 직접 또는 간접적으로 글로벌 Object.prototype을 상속한다. 그러나 Object.create() 메서드를 사용하여 객체의 프로토타입을 생성하여 수동으로 설정할 수도 있다. 이렇게 하면 원하는 객체를 새 객체의 프로토타입으로 지정할 수 있을 뿐만 아니라, 프로퍼티를 전혀 상속하지 않는 null prototype으로 객체를 생성할 수도 있다.
let myObject = Object.create(null);
Object.getPrototypeOf(myObject); // null
Using safer alternatives where possible
prototype pollution에 대한 또 다른 강력한 방어책은 내장된 보호 기능을 제공하는 객체를 사용하는 것이다. 예를 들어 옵션 객체를 정의할 때 Map을 대신 사용할 수 있다. Map은 여전히 악성 속성을 상속할 수 있지만, 맵 자체에 직접 정의된 속성만 반환하는 내장된 get() 메서드가 있다.
Object.prototype.evil = 'polluted';
let options = new Map();
options.set('transport_url', 'https://normal-website.com');
options.evil; // 'polluted'
options.get('evil'); // undefined
options.get('transport_url'); // 'https://normal-website.com'
Key: value 쌍이 아닌 값만 저장하는 경우에는 집합을 사용하는 것도 대안이 될 수 있다. map과 마찬가지로 Set은 객체 자체에 직접 정의된 속성만 반환하는 내장 메서드를 제공한다.
Object.prototype.evil = 'polluted';
let options = new Set();
options.add('safe');
options.evil; // 'polluted';
option.has('evil'); // false
options.has('safe'); // true