설명
외부 엔터티 참조를 허용하는 XML 파서는 공격자가 지정한 파일이나 네트워크 자원에 접근할 수 있습니다. 또한 XML의 크기나 엔터티 확장을 적절히 제한하지 않으면 서비스 거부(DoS)가 발생할 수 있습니다. 실제 위험은 파서의 버전과 설정에 따라 달라집니다.
잠재적 영향
- 데이터 유출: 외부 엔터티를 해석할 수 있는 환경에서는 민감한 파일 내용이 노출될 수 있습니다.
- 서비스 거부: 과도한 입력이나 엔터티 확장으로 서버의 메모리와 CPU가 소진될 수 있습니다.
- 내부 자원 접근: 네트워크 참조를 허용하면 공격자가 서버에서 접근 가능한 자원에 요청을 보낼 수 있습니다.
해결 방법
- 외부 엔터티 해석과 불필요한 DTD 로딩을 비활성화하세요.
- 입력 크기와 처리 자원을 제한하고 파싱 오류를 처리하세요.
- Python과 XML 파서 및 기반 라이브러리를 보안 업데이트가 적용된 버전으로 유지하세요.
예시
lxml
변경 전
python
# XML parsing with the default lxml parser
from lxml import etree
def unsafe_parse(xml_string):
root = etree.fromstring(xml_string)
return root
xml_data = """<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>&xxe;</root>"""
root = unsafe_parse(xml_data)
변경 후
python
# XML parsing without entity expansion
from lxml import etree
def safe_parse(xml_string):
parser = etree.XMLParser(resolve_entities=False, load_dtd=False, no_network=True)
root = etree.fromstring(xml_string, parser=parser)
return root
xml_data = """<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>&xxe;</root>"""
root = safe_parse(xml_data)
설명:
- 변경 전: 기본 파서를 사용합니다. lxml 5.0부터
XMLParser의 기본값은resolve_entities="internal"이므로 외부 파일 엔터티를 읽는 예시로 단정할 수 없습니다. 이전 버전이나 변경된 기본 파서 설정은 별도로 확인해야 합니다. - 변경 후: 엔터티 확장, 외부 DTD 로딩, 네트워크 접근을 명시적으로 비활성화합니다. 더 이상 유지되지 않는
defusedxml.lxml대신lxml의 파서 설정을 직접 사용합니다.
ElementTree
변경 전
python
# XML parsing with standard ElementTree
import xml.etree.ElementTree as ET
def unsafe_parse(xml_string):
root = ET.fromstring(xml_string)
return root
xml_data = """<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>&xxe;</root>"""
root = unsafe_parse(xml_data)
변경 후
python
# Safe XML parsing with defusedxml
from defusedxml.ElementTree import fromstring
def safe_parse(xml_string):
root = fromstring(xml_string)
return root
xml_data = """<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>&xxe;</root>"""
root = safe_parse(xml_data)
설명:
- 변경 전: 표준 ElementTree는 이 외부 엔터티를 확장하지 않고 파싱 오류를 발생시킵니다. 기본 호출만으로 파일 유출이 일어난다는 뜻은 아닙니다.
- 변경 후:
defusedxml.ElementTree는 엔터티 선언 자체를 기본적으로 거부하므로 예시의 입력에EntitiesForbidden예외가 발생합니다. 애플리케이션 경계에서 오류를 처리하고 입력 크기 제한도 별도로 적용하세요.