XML 내부 엔티티 확장으로 인한 서비스 거부 (DoS)

XML Entity Expansion (Billion Laughs)

설명

신뢰할 수 없는 XML을 엔티티 확장이 가능한 상태로 파싱할 때, 공격자가 DTD 내부에 매우 깊이 중첩된 내부 엔티티를 정의하여 작은 입력으로도 기하급수적으로 큰 문자열을 생성하게 만드는 취약점입니다. 이로 인해 파서는 메모리와 CPU를 과도하게 소모하며 서비스 거부(DoS)가 발생합니다. 특히 node-expat처럼 내부 엔티티를 기본 확장하는 파서를 그대로 사용할 경우, 공격자가 빌리언 래프스 형태의 XML을 업로드하거나 전송하는 것만으로 애플리케이션을 멈추게 만들 수 있습니다.

잠재적 영향

  • 서비스 거부(DoS): 과도한 엔티티 확장으로 프로세스가 응답 불가 상태가 됩니다.

  • 메모리 고갈: 확장된 텍스트가 메모리를 점유하여 OOM(메모리 부족)로 프로세스가 종료될 수 있습니다.

  • CPU 자원 고갈: 엔티티 치환/파싱 반복으로 CPU 사용률이 급상승합니다.

  • 시스템 안정성 저하: 애플리케이션 충돌, 자동 재시작 루프, 장애 전파로 가용성이 떨어집니다.

  • 비용 증가: 오토스케일링 환경에서 불필요한 리소스 확장과 비용이 발생할 수 있습니다.

해결 방법

  • 엔티티 확장 비활성화: 가능한 경우 XML 파서 옵션에서 DTD/Entity 확장을 끄고, DOCTYPE 선언을 거부합니다.

  • 안전한 파서 사용: node-expat처럼 내부 엔티티를 기본 확장하는 라이브러리 대신 sax 같은 스트리밍 파서(사용자 정의 엔티티를 확장하지 않음) 또는 엔티티 확장 제어가 가능한 파서를 사용합니다.

  • 입력 제한: 요청 본문 크기(limit), 파싱 시간(timeout), 노드/깊이/텍스트 길이 제한을 적용합니다.

  • 유효성 검증: 스키마(whitelist) 검증을 적용하고, 입력 내 <!DOCTYPE 등 DTD 관련 토큰이 발견되면 요청을 거부합니다.

  • 방어적 구성: 리버스 프록시/웹서버에서 요청 크기 제한, 애플리케이션에서 작업 큐와 동시성 제한으로 폭주를 억제합니다.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: node-expat는 내부 엔티티를 기본적으로 확장합니다. 검증 없이 req.body를 그대로 전달하면, 공격자가 중첩된 엔티티(빌리언 래프스)를 포함한 XML을 보내 작은 입력으로도 메모리/CPU를 고갈시켜 DoS를 유발합니다.

  • 안전한 코드: - DOCTYPE/ENTITY가 포함된 XML을 사전에 차단해 DTD 기반 엔티티 확장을 원천 봉쇄합니다.

  • sax 같은 스트리밍 파서는 사용자 정의 엔티티를 확장하지 않아 내부 엔티티 확장 공격에 강합니다.

  • 요청 본문 크기 제한으로 대용량 입력을 차단하고, 오류 처리를 통해 파싱 중단이 가능합니다.

참조

Last updated