XXE:XML 解析器的「默认太信任」
XML 解析器默认允许外部实体,这是历史设计。于是一个看起来无害的「导入 XML」功能,能读出服务器上的文件。
更麻烦的是它可以与 SSRF 组合:用实体发请求,把内网响应带进错误信息里。
先说结论
禁用 DTD 与外部实体,能换 JSON 就换。 配置开关比过滤字符串可靠得多。
- 解析器显式关闭外部实体与 DTD
- 不接受用户提供的 DTD
- 错误信息不回显解析细节
- 新接口优先 JSON
漏洞是怎么产生的
XXE 的载荷通常藏在 DOCTYPE 里:定义实体指向 file:// 或 http://,然后在文档里引用。
因为解析发生在「业务逻辑之前」,很多输入过滤根本来不及生效。
修复与验证
修复不是改一行代码,而是四件事一起做:
- 盘点所有 XML 解析点:接口、配置文件、SOAP、Office 文档解析
- 关闭 DTD 与外部实体(各语言有对应开关)
- 限制解析深度与实体展开次数,防 billion laughs
- 错误响应统一化,不回显解析器原始报错
- 对外接口改用 JSON
攻击面与检测点
按影响面排序,先修影响最大的:
| 语言 | 配置 | 说明 |
|---|---|---|
| Java | disallow-doctype-decl=true | 首选彻底禁用 |
| PHP | libxml_disable_entity_loader(true) | 老版本必需 |
| Python | defusedxml | 替换标准库 |
| .NET | DtdProcessing=Prohibit | XmlReaderSettings |

几个容易踩的坑
下面这些是最常见的错误做法:
- 只过滤 <!ENTITY:编码与参数实体可绕
- 用一个解析器禁用、另一个没禁用
- 认为只有 SOAP 才有 XML:Excel/Word 解析同样中招
- 错误信息直接返回给前端
写在最后
XXE 的修复是最「配置化」的:打开一个开关就能根治,难的是把所有解析点都找全。
安全不是一次加固,是持续的假设:假设输入不可信、假设边界会破、假设有人会看错。
评论 (3)
修复清单比漏洞描述有用多了,很多文章只讲怎么打不讲怎么防。
白名单那条永远是最有效的,正则黑名单迟早绕过。
建议再补一条:把这类检查加到 CI 里,靠人记必然漏。
发表评论