Quick Flow
신뢰할 수 없는 JSON 처리
1. Content-Type은 계약으로 확인하고 body 크기와 압축 해제 크기를 먼저 제한한다
2. JSON parser로 파싱하고 eval은 쓰지 않는다
3. 최대 크기, 중첩 depth, array 길이를 제한한다
4. schema나 명시적 allowlist로 구조를 검증한다
5. __proto__, constructor, prototype 같은 위험 key를 merge 전에 차단한다
6. 외부 `$ref`와 오류 응답은 네트워크 접근·내부 정보를 노출하지 않게 제한한다방어 기준
JSON은 데이터 형식이지 실행 코드가 아니다
외부에서 받은 JSON 문자열을 eval()로 처리하면 데이터 파싱이 아니라 코드 실행 문제가 됩니다. JSON parser를 사용하면 문법적으로 허용된 JSON text만 값으로 바뀌고, 실패 시 파싱 오류로 다룰 수 있습니다. 보안 경계에서는 "문자열을 실행하지 않는다"가 첫 번째 기준입니다.
파싱 성공도 충분한 검증은 아닙니다. { "role": "admin" }은 유효한 JSON이지만 현재 endpoint가 받을 수 있는 payload인지는 별도 계약 문제입니다. 파싱 후에는 schema 검증이나 allowlist 기반 필드 검증이 필요합니다.
크기와 depth 제한이 없으면 parser 자체가 부담이 된다
JSON은 텍스트 형식이라 매우 큰 array, 깊은 중첩 object, 긴 문자열을 만들기 쉽습니다. parser가 입력을 모두 메모리에 올리는 구현이라면 작은 API endpoint도 큰 body 하나로 메모리와 CPU를 많이 사용할 수 있습니다. HTTP layer에서 body size limit을 두고, 애플리케이션 layer에서 depth와 array 길이, string 길이 제한을 별도로 확인하는 편이 안전합니다. gzip 같은 압축 body는 전송 크기만 보고 통과시키면 압축 해제 뒤 훨씬 큰 입력이 될 수 있으므로, 해제 후 크기와 처리 시간도 제한합니다.
제한할 지점
- 요청 body byte 크기
- object/array 중첩 depth
- array 최대 item 수
- string 최대 길이
- 한 요청에서 처리할 document 수
- 압축 해제 후 최대 byte와 parse 시간merge 전에는 위험 key를 차단한다
JavaScript 환경에서는 JSON으로 들어온 object를 설정 object나 prototype이 있는 object에 깊게 merge할 때 prototype pollution 위험이 생길 수 있습니다. __proto__, constructor, prototype 같은 key는 일반 데이터처럼 보이지만 merge 로직에 따라 object prototype에 영향을 줄 수 있습니다. 외부 JSON을 내부 설정과 합치기 전에는 allowlist로 허용 key를 제한하거나, prototype 없는 object와 안전한 merge 함수를 사용합니다.
schema resolver와 오류 메시지도 입력 경계다
validator가 외부 $ref URI를 자동으로 가져오면 공격자가 내부 주소나 느린 외부 주소로 요청을 유도할 수 있습니다. schema는 미리 등록하거나 allowlist로 제한하고, resolver에는 URL·응답 크기·시간 제한을 둡니다. parse와 validation 오류를 응답할 때도 원본 body, 내부 경로, stack trace를 그대로 돌려주지 말고 request ID와 안전한 오류 code만 공개합니다.
어디서 막을까
| 위험 | 방어 위치 |
|---|---|
| 잘못된 media type | HTTP header 확인 |
| 너무 큰 body | reverse proxy 또는 server body limit |
| 압축 폭탄과 긴 parse | 해제 후 크기, 시간, CPU 제한 |
| 깊은 중첩과 긴 array | parser 전후 size/depth 제한 |
| 예상 밖 field | JSON Schema 또는 allowlist |
| 위험 key merge | merge 전 key 필터링 |
| 외부 schema 참조 | 사전 등록 또는 resolver allowlist |
| HTML 에러를 JSON으로 파싱 | 응답 Content-Type 확인 |
주의할 점
JSON parser를 통과했다는 것은 문법이 맞다는 뜻일 뿐입니다. 보안 경계에서는 문법 검증, 구조 검증, 크기 제한, merge 안전성 검사를 별도 단계로 나눠야 합니다.
const input = JSON.parse(text);
// 위험: 외부 입력을 그대로 설정 object에 깊게 merge
deepMerge(config, input);외부 JSON을 내부 object에 합칠 때는 허용 key만 남기고, prototype 관련 key를 차단한 뒤 merge해야 합니다.
참고 링크
2 sources