Javascript Prototype 오염

2022. 4. 21. 17:00프론트엔드/HTML, CSS, Javascript

728x90

면접에서 몰랐던 부분이라 한 번 찾아봤다.


 

 

Node.js에서의 프로토타입 오염 공격이란 무엇인가

__proto__을 이용한 프로토타입 오염(prototype pollution) 공격의 원리를 설명하면서 노드 환경에서 실제 공격이 가능한 사례를 함께 소개합니다.

blog.coderifleman.com

4줄 요약하면 다음과 같다.
혹시 모르니 코드로도 써놓겠다.

const a = {};
a.__proto__ === Object.prototype
a.__proto__.goldfish = "good"
Object.prototype.goldfish

 한줄 한줄 살펴보자


const a = {};

a라는 변수를 객체 리터럴로 선언을 하였다.
객체 리터럴이란 ECMAScript 2015에서 지원된 방법으로,
기존 생성자를 이용하지 않고 중괄호로 표현하는 방식이다.

const a = {}
const b = { a: 4 }

이 오염 이슈는 객체 리터럴에서 발생한다.
왜냐하면 객체 리터럴로 생성된 객체의 __proto__는
Object.prototpe과 같기 때문이다.


a.__proto__ === Object.prototype

두번째 줄은 실제로 객체 리터럴로 생성된 a의 __proto__와
Object.prototype이 같은지 보는 것이다.

참고로 결과는 참이다.


 a.__proto__.goldfish = "good"

세번째 줄에서는 a.__proto__goldfish라는 프로퍼티를 넣었다.


 Object.prototype.goldfish

그랬더니 실제로 Object.prototype.goldfish가
세번재 줄에서 대입한 "good"이 된 것을 알 수 있다.


그래서?

그러고 보니 Object.prototype이 바뀐게 무슨 소용인가 싶을 수 있다.
이 세가지를 생각해보자

프로토타입의 프로퍼티는 해당 프로토타입을 가지는 모든 객체가 사용할 수 있다.

이런 식으로 어떤 리터럴 객체를 생성하던간에
goldfish의 값을 가지고 있음을 알 수 있다.

그림 설명


오염 방법

근데 물론 이건 코드에서 실행하지 않으면 의미가 없다.
그렇기 때문에 어떻게든 실행시키기 위해 이런 방법을 쓴다.

a[id][name] = valueFromFront;

별 문제 없어보인다.
하지만 값이 다음과 같다면 어떻게 될까?

const id = "__proto__";
cosnt name = "goldfish";
const valueFromFront = "good";

a[id][name] = valueFromFront;
// a["__proto__"]["goldfish"] = "good"

징하다 진짜...

기타 방식으로는 객체를 깊은 복사하거나,
객체에 key를 넣는 유틸함수을 이용해 적용시킬 수 있다.


해결 방법

1. Object.freeze를 이용해 변경을 못하게 한다.
2. 외부에서 들어오는 입력값을 검증한다 (avj 등)
3. key / value를 저장하는데 객체를 사용하지 않고 Map을 사용한다.


후기

이런거 뚫는 사람들 정말 대단한 사람들이라는 생각이 들고,
왜 면접에서 Typescript의 장점이나 ~하지 않는 이유같은 걸
계속해서 물어봤는지 알 것 같다.