소프트웨어 개발보안 가이드 분석(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 삽입