XML 외부 엔터티(XXE) 취약점

XML External Entity (XXE)

설명

XML External Entity(XXE) 취약점은 XML 파서가 외부 엔터티(External Entity)를 허용할 때 발생합니다. 외부 엔터티는 XML 안에서 파일 시스템, HTTP 등 외부 자원을 참조할 수 있게 하는 기능입니다. 공격자가 직접 조작한 XML을 애플리케이션에 보내고, 이 XML을 외부 엔터티 허용 상태로 파싱하면, 서버 내부 파일 읽기, SSRF(내부망 요청), 서비스 거부(DoS) 등이 발생할 수 있습니다. 이 Semgrep 룰은 Go에서 github.com/lestrrat-go/libxml2/parser 사용 시 parser.New(parser.XMLParseNoEnt) 옵션으로 외부 엔터티 파싱을 켠 경우를 탐지합니다. 이 상태에서 사용자 입력 XML을 그대로 파싱하면 XXE 공격에 취약해집니다.

잠재적 영향

  • 민감 정보 노출: XML 외부 엔터티를 이용해 서버의 /etc/passwd, 설정 파일, 소스 코드 등 내부 파일을 읽어 공격자에게 전송할 수 있습니다.

  • 서버사이드 요청 위조(SSRF): 외부 엔터티 URL을 내부 시스템(예: http://127.0.0.1:8080/admin)로 지정해, 외부에서는 접근 불가능한 내부 서비스에 간접 요청을 보낼 수 있습니다.

  • 서비스 거부(DoS): 매우 큰 엔터티 확장 또는 엔터티 폭탄(XML Bomb)을 사용해 파서를 과도하게 사용하게 만들어 CPU·메모리 자원을 소진시키고 서비스 중단을 유발할 수 있습니다.

해결 방법

  • 기본적으로 외부 엔터티 비활성화: 가능하면 외부 엔터티 관련 옵션(XMLParseNoEnt 등)을 사용하지 않습니다.

  • 라이브러리 보안 옵션 사용: 사용하는 XML 파서(libxml2 기반 라이브러리 포함)의 XXE 방지 옵션(외부 엔터티 비허용, 네트워크 접근 차단 등)을 확인하고 활성화합니다.

  • 신뢰되지 않은 입력 분리: 사용자로부터 받은 XML은 가능한 한 파싱하지 않거나, 반드시 검증·필터링 후에만 제한된 스키마에 맞게 처리합니다.

  • 필요 최소 권한: 애플리케이션 계정에 파일 시스템 최소 권한만 부여해, XXE로 읽히더라도 영향 범위를 줄입니다.

  • 보안 테스트: XXE 전용 테스트 페이로드(DTD, 외부 엔터티 포함 XML)를 활용해 정기적으로 애플리케이션을 점검합니다.

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

취약한 코드

안전한 코드

설명:

  • 취약한 코드: 취약한 코드에서는 parser.New(parser.XMLParseNoEnt)를 사용해 XML 파서를 생성합니다. XMLParseNoEnt 옵션은 외부 엔터티를 실제 값으로 확장하도록 허용하는 플래그입니다.

이 상태에서 사용자가 보낸 XML을 그대로 ParseString에 전달하면, 공격자가 다음과 같은 XML을 보낼 수 있습니다.

파서는 &x;를 실제 파일 내용으로 치환하려 시도하고, 결과적으로 내부 파일이 읽히고 애플리케이션 로직에 따라 공격자에게 노출될 수 있습니다. 즉, 외부 엔터티 활성화 + 사용자 입력 직접 파싱 조합이 XXE 취약점을 만듭니다.

  • 안전한 코드: 안전한 코드에서는 parser.New()만 사용하고 XMLParseNoEnt 옵션을 주지 않습니다. 이로 인해 외부 엔터티가 자동으로 확장되지 않아, 공격자가 정의한 SYSTEM 엔터티를 통해 내부 파일을 읽는 공격이 차단됩니다.

또한 입력을 파싱하기 전에 전체 바이트를 읽고 에러를 확인하는 등 기본적인 검증을 수행할 수 있는 구조로 만들어, 추가적으로 크기 제한이나 Content-Type 체크, 스키마 검증 등을 쉽게 넣을 수 있습니다. 이 방식은 XXE를 포함한 XML 관련 취약점을 줄이는 실무적인 방어 방법입니다.

참조

Last updated