XXE漏洞是什么 如何在解析XML时防范它

1次阅读

XXE漏洞本质是xml解析器无条件加载攻击者控制的外部实体,需禁用DOCTYPE声明及所有外部实体相关特性。java中须组合设置多个setFeature为false并禁用XInclude;python lxml需显式设resolve_entities=False和no_network=True;最彻底防御是在解析前过滤或拒绝含DOCTYPE的请求。

XXE漏洞是什么 如何在解析XML时防范它

XXE漏洞本质是xml解析器加载了恶意外部实体

XXE(XML External Entity)不是XML语法错误,而是解析器在处理声明时,无条件加载了攻击者控制的SYSTEMpublic外部实体。典型后果包括读取本地文件(如/etc/passwd)、发起内网SSRF、触发dns外带、甚至导致拒绝服务。

Java中使用DocumentBuilder时必须禁用外部DTD和实体

默认的DocumentBuilderFactory开启外部实体解析,且setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)在老版本JDK(如JDK 6/7)上不生效。真正有效的组合是:

DocumentBuilderFactory factory = DocumentBuilderFactory.newinstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); factory.setXIncludeAware(false); factory.setExpandEntityReferences(false);
  • disallow-doctype-decl应设为true,但仅靠它不够——某些老解析器仍会尝试解析已存在的DOCTYPE
  • external-general-entitiesexternal-parameter-entities必须显式设为false,否则ENTITY声明仍可被解析
  • load-external-dtd设为false防止加载外部DTD文件,哪怕DOCTYPE存在

Python中lxml和xml.etree.ElementTree的差异很关键

xml.etree.ElementTree默认不解析外部实体,相对安全;但lxml(尤其搭配etree.XMLParser())默认启用,并支持resolve_entities=True(默认值)。必须显式关闭:

from lxml import etree parser = etree.XMLParser(     resolve_entities=False,     no_network=True,     dtd_validation=False,     load_dtd=False ) tree = etree.parse("input.xml", parser)
  • resolve_entities=False是核心开关,漏掉它就等于没防
  • no_network=True阻止解析器访问网络资源(如http://attacker.com/evil.dtd
  • 即使传入remove_comments=Trueremove_pis=True,也不影响XXE防护,别混淆关注点
  • 若用etree.fromstring(),必须传入同一parser实例,不能依赖全局默认

所有场景下都该禁用DOCTYPE声明本身

最彻底的防御不是“解析但不加载外部实体”,而是根本不让DOCTYPE进入解析流程。多数现代XML解析器支持“无DOCTYPE模式”或预过滤:

  • 对不可信输入,在解析前用正则粗筛:re.sub(r'', '', xml_str, flags=re.DOTALL) + re.sub(r'^>]*>', '', xml_str)(注意:仅作辅助,不能替代解析器配置)
  • spring Framework中,@RequestBody绑定XML时,应配置Jaxb2RootElementHttpMessageConverter并设置setSupportDtd(false)
  • 若业务根本不需要DOCTYPE(如纯数据交换),在API层直接拒绝含/code>的请求体,HTTP 400响应并记录日志

很多团队只关了external-entities,却忘了DOCTYPE本身可能触发解析器初始化逻辑,或暴露内部路径信息。真正安全的起点,是让恶意声明根本进不了解析器。

text=ZqhQzanResources