소프트웨어 개발보안 가이드 분석(2021) : 부적절한 XML 외부개체 참조

XML 문서에는 DTD(Document Type Definition)를 포함할 수 있으며, DTD는 XML 엔티티(Entity)를 정의한다.

부적절한 XML 외부개체 참조 보안약점은 서버에서 XML 외부 엔티티를 처리할 수 있도록 설정된 경우에 발생할 수 있다.

소프트웨어 개발보안가이드(2021), 한국인터넷진흥원

XML 엔티티(Entity)란, XML 문서 내에서 데이터를 나타내는 방법 중 하나입니다. 반복적인 문장이나 문자열을 저장해놓고 쉽게 참조할 수 있는 용도로 많이 사용됩니다. 이런 XML 엔티티에는 내부 엔티티와 외부 엔티티 두 가지 유형이 있습니다. 그중 취약한 XML 파서(Parser)가 외부 엔티티를 참조하는 XML 데이터를 처리할 때 공격자가 삽입한 외부 엔티티가 동작하는 방식입니다.

※ XML 파서(Parser) : 텍스트 형식으로 작성되는 XML 문서를 읽고 해석하여 컴퓨터가 이해하도록 처리하는 프로그램 또는 라이브러리.

이번 포스팅에서는 XML 엔티티에 대하여 취약한 코드 예제와 이를 방지하기 위한 안전한 코드 작성 방법을 살펴보려고 합니다.

XML 엔티티(Entity)

  1. 내부 엔티티 : DTD 내부에서 직접 정의되고 사용되는 엔티티입니다.
  2. 외부 엔티티 : XML 문서 외부에 정의되고 XML 파서가 문서를 파싱하는 동안 로드할 수 있는 엔티티입니다. 외부 자원(파일, URL 등)을 참조할 수 있기 때문에 공격자는 악의적인 자원을 참조 시켜 공격을 수행하며 SYSTEM 키워드를 사용하여 정의합니다.
내부 엔티티(Internal) 정의와 외부 엔티티(External) 정의 차이

취약한 코드 예시

   1     File xmlFile = new File("xml 파일");

   2     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   3     DocumentBuilder builder = factory.newDocumentBuilder();
   4     Document document = builder.parse(xmlFile);

   5     System.out.println(document.getDocumentElement().getTextContent());

1행 : 위의 코드에서 외부 엔티티(External)로 선언된 xml 파일을 File 객체로 생성합니다.

2~4행 : builder 객체를 사용하여 XML 파일을 파싱하여 document 객체를 생성합니다.

5행 : XML 문서의 모든 텍스트 내용을 가져와 출력합니다.

XML 문서에는 <foo>안에 &External 엔티티는 'file:///etc/passwd'를 참조하도록 정의되어 있어 /etc/passwd 파일의 내용이 출력되어 보안상 매우 취약합니다.

위험성

  1. 외부 엔티티 참조를 통한 파일 시스템 접근 : 공격자는 외부 엔티티 참조를 이용하여 시스템 파일에 접근하거나 실행할 수 있습니다. 이를 통해 개인정보가 포함된 파일에 접근하거나 시스템을 손상시킬 수 있습니다.
  2. 외부 DTD 로딩을 통한 원격 서버 연결 : XML 파서가 외부 DTD를 로드할 때, 악의적인 DTD를 포함한 외부 서버와 연결할 수 있습니다. 이를 통해 악성코드를 실행하거나 외부 공격을 수행할 수 있는 위험이 발생할 수 있습니다.
  3. 서비스 거부(DoS) 공격 : 공격자는 외부 엔티티 참조를 통해 시스템 리소스를 과도하게 사용하거나 과부하를 유발해 서비스 이용에 장애를 발생시킬 수 있습니다.

예방 방법 및 안전한 코드 작성 사이드

1. 외부 엔티티 참조 비활성화

1     factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
2     factory.setXIncludeAware(false);
3     factory.setExpandEntityReferences(false);
  • 1행 : DTD 선언을 허용하지 않도록 설정합니다. 즉, XML 문서 내에서 DTD를 사용할 수 없게 됩니다.
  • 2행 : 외부 엔티티 참조에 대한 XInclude 처리를 비활성화합니다.
  • 3행 : 확장 엔티티 참조를 비활성화합니다.
  • XML 문서 내에서 외부 엔티티를 참조하는 기능을 비활성화하여 XML 파서가 외부 엔티티를 해석하지 않고, 오직 내부에 포함된 데이터만을 처리할 수 있도록 보장할 수 있습니다.

2. 사용자 정의 엔티티 처리

1 builder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
  • 1행 : setEntityResolver 메서드를 사용하여 사용자 정의 엔티티 처리를 설정합니다.
  • publicId, systemId를 입력으로 받아서 사용자가 원하는 문자열로(해당 코드에선 빈 문자열) 리턴하는 InputSource를 생성합니다. 이를 통해 모든 엔티티 참조를 사용자가 정의한 문자열로 대체할 수 있습니다.

3. DTD 검사 비활성화

1 factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
  • 1행 : setFeature 메서드를 사용하여 DTD 검사를 비활성화 시킵니다.
  • "http://apache.org/xml/features/nonvalidation/load-external-dtd"를 통해 외부 DTD 로딩 기능을 비활성화시켜 XML 파서가 외부 DTD는 무시하고 오직 내부에 포함된 DTD만 처리하게 됩니다.

4. Secure Processing 모드

1 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
  • 1행 : XML 파서를 Secure Processing 모드로 설정하여 XML 보안을 강화합니다.
  • Secure Processing 모드의 경우 위에서 설명드린 외부 엔티티 참조 비활성화, DTD 검사 비활성화 등을 포함하여 XML 파서의 보안을 강화하는 방법입니다. 그러므로 Secure Processing을 활성화하는 것이 가장 간단하고 효율적인 방법이라 할 수 있습니다.

  • 이전 소프트웨어 개발보안 가이드 분석(2021) : 신뢰되지 않은 URL 주소로 자동접속 연결
  • 다음 소프트웨어 개발보안 가이드 분석(2021) : XML 삽입