xml.etree.elementtree 默认不安全,因其默认启用dtd解析和实体展开,易受xxe攻击;应改用defusedxml.elementtree并禁用外部实体、限制节点深度等。

为什么 xml.etree.ElementTree 默认不安全
Python 标准库的 xml.etree.ElementTree 在解析外部实体(XXE)或大量嵌套节点时,会直接执行 DTD 声明、加载远程资源、展开实体——这等于把解析器变成攻击入口。常见现象是:程序突然发起外网请求、内存暴涨崩溃、甚至读取本地文件(如 file:///etc/passwd)。根本原因不是它“有漏洞”,而是它默认开启 DTD 解析和实体展开,而多数业务根本不需要这些功能。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 只要 XML 来源不可信(用户上传、HTTP 回包、第三方 API),就绝不能直接用
ET.parse()或ET.fromstring() - 禁用 DTD 的最简方式是传入自定义
XMLParser,并设resolve_entities=False和strip_cdata=False(后者防 CDATA 逃逸) - 但更稳妥的做法是换用
defusedxml——它不是“增强版标准库”,而是从解析器底层重写防御逻辑
用 defusedxml.ElementTree 替代原生解析器
这是最常用也最直接的迁移路径。它完全兼容 xml.etree.ElementTree 的 API,只需改导入和函数名,不用动业务逻辑。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 安装:
pip install defusedxml - 替换导入:
from defusedxml.ElementTree import parse, fromstring(不是import defusedxml.ElementTree as ET,否则仍可能误用原生类) - 注意:
defusedxml.ElementTree不支持iterparse(),如果代码里用了流式解析,得换成defusedxml.cElementTree或改用SAX方式 - 参数差异:它默认禁用 DTD、外部实体、注释、CDATA 展开,且对节点深度、属性数量、文本长度做了硬限制(可调,但别轻易放宽)
解析失败时看到 DefusedXmlException 怎么办
这不是 bug,是防御机制在起作用。典型错误信息像:defusedxml.common.DefusedXmlException: Maximum depth exceeded 或 Entity 'xxx' not found。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认 XML 是否真合法:用在线 XXE 检测工具(如
xxe-exploiter)扫一遍,排除恶意构造 - 如果是合法但结构复杂(比如深度 > 100 的嵌套、超长 base64 文本),再考虑调参,例如:
from defusedxml.ElementTree import ParseError<br>from defusedxml.common import EntitiesForbidden<br><br># 允许更深的树(慎用)<br>parser = XMLParser()<br>parser.parser.UseForeignDTD(False)<br>parser._parser.DefaultHandler = None<br>parser._parser.SetParamEntityParsing(0)
- 更推荐做法:在解析前用正则或简单字符串扫描预检——比如拒绝含
/code>、<code><?xml. *?encoding(非 UTF-8)、SYSTEM的 XML
还有哪些地方容易漏掉防御
很多人只改了主解析入口,却忘了其他 XML 相关模块也在悄悄干活。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 检查是否用了
xml.dom.minidom:必须换成defusedxml.minidom,否则minidom.parse()依然危险 - 检查是否用了
lxml:它默认也不安全,需显式关闭 DTD:etree.XMLParser(resolve_entities=False, no_network=True) - 检查 Web 框架层:Django 的
django.http.HttpRequest.body或 Flask 的request.data如果被直接喂给 XML 解析器,同样需要前置过滤 - 特别注意测试用例:很多单元测试用硬编码 XML 字符串,里面带
&xxe;实体,一跑就触发异常——这不是问题,是测试在帮你暴露风险
真正麻烦的从来不是加一行 from defusedxml...,而是得逐个确认所有 XML 进口点、所有依赖库的解析行为、所有测试数据的合法性。漏掉任意一个,前面的防护就形同虚设。










