XXE 修复的核心是什么
XXE 的根因是 XML 解析器默认允许外部实体:文档里声明的实体可以被解析器去读取本地文件或发起网络请求,解析结果一旦回显到响应里,就形成文件读取或服务端请求伪造。最直接的修复是在解析器层面关闭 DTD 与外部实体,其次是升级存在已知问题的解析库,最后是把安全配置封装成统一的工具函数——大量入口分散在业务代码与框架封装里,逐处修改必然会漏。
基本信息
| Java 侧 | 设置 disallow-doctype-decl 等安全特性,关闭外部实体与外部 DTD |
|---|---|
| Python 侧 | 确认所用解析器是否处理外部实体,按官方文档关闭 |
| PHP 侧 | 使用 libxml 时确认外部实体加载开关的默认行为 |
| 统一措施 | 把安全解析封装成公共函数,禁止业务代码自行 new 解析器 |
| 前提 | 先确认解析器与版本,再决定配置项,不同版本特性支持不同 |
典型使用场景
- 代码审计中定位 XML 解析入口并统一加固
- 修复评审时判断「过滤字符串」方案是否足够
- 排查框架封装的 XML 转换入口(SOAP、报表、配置导入)
- 升级解析库后的配置复核:默认行为仍可能允许外部实体
- 为接口清单补充 XML 入口:很多系统只关注 JSON 接口而漏掉 XML
Java 修复示意
Java 修复示意
// 仅展示方向,配置项名称与可用性依解析器与版本而定,勿照搬到未知版本
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// 依据解析器类型补充关闭外部实体的相关特性(外部通用实体、参数实体、外部 DTD)
f.setXIncludeAware(false); // 关闭 XInclude,它可绕过部分实体限制
f.setExpandEntityReferences(false); // 不展开实体引用
// 建议:把上述配置封装成统一的解析工具,业务代码只调用该工具入口与检查点
| 入口类型 | 检查点 |
|---|---|
| 直连 XML 接口 | 解析器安全特性是否显式关闭 DTD 与外部实体 |
| 框架封装的转换 | SOAP、报表导出、配置导入等链路的底层解析配置 |
| 第三方库内部解析 | 确认库版本与默认行为,必要时升级到已加固版本 |
| 文件上传解析 | docx/xlsx 等压缩包内 XML 是否经同一安全解析路径 |
仅过滤字符串里的实体声明不充分:编码、参数实体与嵌套 DTD 等写法多样,应从解析器配置层面关闭能力。
升级了库但未改配置,默认行为可能仍解析外部实体:升级与配置是两件事,需要分别确认。