Java 防 XXE 攻击需禁用外部实体和 DTD 解析:对 DocumentBuilder、SAXParser、Transformer 等均须显式关闭相关特性;推荐 Jackson XML 或 DOM4J 并配合白名单 EntityResolver、输入校验与 WAF 防护。

Java 中防止 XXE(XML External Entity)攻击,核心是禁用外部实体解析和 DTD 处理。默认的 XML 解析器(如 JAXP 中的 DocumentBuilder、SAXParser、Transformer)若未显式配置,可能启用外部实体,导致敏感文件读取、SSRF 甚至远程代码执行。
禁用外部实体和 DTD 解析
对所有 XML 解析器实例,必须显式关闭 http://apache.org/xml/features/disallow-doctype-decl 和http://xml.org/sax/features/external-general-entities等关键特性:
- DocumentBuilder:设置
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true),再设setFeature("http://xml.org/sax/features/external-general-entities", false) - SAXParser:在
SAXParserFactory上调用setFeature(),同样禁用上述两项,以及http://xml.org/sax/features/external-parameter-entities - Transformer(用于 XSLT):通过
TransformerFactory设置FEATURE_SECURE_PROCESSING为true,并禁用http://javax.xml.XMLConstants/feature/secure-processing
使用白名单机制替代通用解析
如果业务必须处理带 DOCTYPE 的 XML(极少见),不要开放全部实体,而是采用白名单方式预定义允许的实体,并重写EntityResolver:
- 实现
org.xml.sax.EntityResolver,对resolveEntity方法只返回已知安全的InputSource - 拒绝所有
systemId含file://、http://、https://或jar:的请求 - 避免调用
new InputSource(new FileInputStream(……))等直接加载路径的操作
优先选用现代、安全默认的库
避免依赖老版本 JDK 或未加固的第三方 XML工具:
立即学习“Java 免费学习笔记(深入)”;
- JAXB(
Unmarshaller)需配合SecurityManager或显式禁用外部实体;JDK 17+ 已弃用,建议迁移到 Jackson XML 或 DOM4J(配置后) - 推荐 Jackson XML(
jackson-dataformat-xml):默认不解析 DTD,且可通过XmlFactory关闭XMLStreamConstants.FEATURE_DOCTYPE_DECLARATION - DOM4J 2.1.4+ 默认禁用外部实体,但仍建议调用
DocumentHelper.parseText(xml).setEntityResolver(null)并校验输入
补充防御:输入验证与运行时限制
解析前加一层过滤,能显著降低风险:
- 用正则或 XML Schema(XSD)预校验 XML 结构,拒绝含
/code>、的输入 - 在容器或 JVM 层启用
SecurityManager(虽已废弃,但在受限环境仍可限制FilePermission) - 生产环境部署 WAF 规则,拦截常见 XXE 载荷如
]]>
基本上就这些。关键不是“怎么解析 XML”,而是“怎么确保它不会去碰不该碰的东西”。每种解析器都得单独配,不能只改一处就以为全安全了。