Java解析XML必须禁用XXE并限制资源消耗,否则可能导致信息泄露、DoS或RCE;需通过设置features禁用DOCTYPE和外部实体,限制解析深度与大小,优先使用StAX流式解析,并叠加专用安全库与运行时防护。

Java解析XML时,必须禁用外部实体(XXE)并限制解析器资源消耗,否则可能引发敏感信息泄露、服务拒绝(DoS)甚至远程代码执行。
禁用XXE:关闭外部实体和DTD处理
默认的JAXP解析器(如DocumentBuilder、SAXParser、XMLReader)可能启用DTD和外部实体解析,这是XXE漏洞的根源。关键操作是显式配置解析器工厂,关闭相关功能:
- 对red">DocumentBuilderFactory:调用
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)禁用DOCTYPE声明;再设setFeature("http://xml.org/sax/features/external-general-entities", false)和setFeature("http://xml.org/sax/features/external-parameter-entities", false) - 对SAXParserFactory:同样设置上述三个feature为false
- 对TransformerFactory(用于XSLT):调用
setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true),并禁用扩展函数(setAttribute("http://javax.xml.transform.TransformerFactory/feature/enable-integration", false))
防御DoS:限制解析深度、大小与实体展开
攻击者可通过递归实体、超长文本或深层嵌套标签耗尽内存或CPU。需主动设限:
- 设置
ENTITY expansion limit:JDK 8u191+支持setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false)配合setFeature("http://apache.org/xml/features/security/max-entity-depth", 5)等(需使用Xerces或较新JDK) - 限制输入长度:在解析前检查XML字节数(如
inputStream.available()不准确,建议用BufferedInputStream读取头若干KB判断是否过大) - 避免使用
DOM解析超大XML;优先选SAX或StAX流式解析,它们不一次性加载全部节点到内存
推荐安全解析方式:优先使用StAX或白名单DOM
StAX(Streaming API for XML)天然不易受XXE影响,且可控性强:
立即学习“Java免费学习笔记(深入)”;
- 用
XMLInputFactory.newFactory()获取工厂后,立即调用factory.setProperty(XMLInputFactory.SUPPORT_DTD, false)和factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false) - 若必须用DOM,只允许解析已知结构的XML,并配合Schema或XSD校验;解析后手动遍历检查是否存在
ENTITY、SYSTEM等危险关键字 - 永远不要用
javax.xml.parsers.DocumentBuilder.parse(new InputSource(new StringReader(userInput)))这类直接解析不可信字符串的方式
额外加固:使用专用安全库与运行时防护
依赖JDK默认配置风险高,建议叠加防护层:
- 引入OWASP Java HTML Sanitizer或Apache Commons Text预处理XML字符串,移除DOCTYPE、ENTITY声明
- 在应用层设置超时与线程限制:如用
ExecutorService包装解析任务,设定maxWait与timeout - JDK 9+启用
--add-opens java.xml/com.sun.org.apache.xerces.internal.impl仅当必须调用内部类;但更推荐升级到JDK 17+,其默认开启更多安全特性










