导读:本期聚焦于小伙伴创作的《Java DocumentBuilderFactory如何配置安全特性防止XXE攻击》,敬请观看详情。把外部实体默认开启的XML解析器直接用于业务接口,等于给服务器留了一道任意文件读取的后门。DocumentBuilderFactory在解析XML时若未显式禁用DOCTYPE,攻击者可构造恶意实体加载本地文件或发起内网请求。实际配置中应调用setFeature关闭外部通用实体与外部参数实体,并配合setExpandEntityReferences(false)降低风险。不同JDK版本对默认策略存在差异,仅靠升级并不能彻底免疫。通过显式设置XMLConstants相关安全属性,才能在解析用户上传的XML时阻断实体展开,保障应用边界不被穿透。

在Java应用中处理XML是极为常见的需求,无论是WebService报文、配置文件还是第三方数据交换,都离不开解析器。DocumentBuilderFactory作为JAXP规范提供的工厂类,负责创建DOM解析器实例。它的默认配置在不同历史版本中并不一致,早期版本会默认允许处理文档类型定义(DTD)中的外部实体,这就为XXE(XML External Entity)注入攻击打开了通道。攻击者只需在XML中嵌入指向本地敏感文件或内部服务的实体声明,就能在解析阶段触发任意文件读取或服务端请求伪造。

Java DocumentBuilderFactory如何配置安全特性防止XXE攻击

一、XXE攻击的基本原理与危害

XXE攻击的核心在于利用XML解析器对外部实体的支持。当一个XML文档包含<!DOCTYPE>声明,并在其中定义指向外部资源的实体时,若解析器被配置为展开该实体,就会主动去获取对应资源。例如定义实体指向file:///etc/passwd,解析后该实体的内容会被替换进DOM树,接口返回时便泄露了系统文件。更进一步,攻击者还能利用http或ftp协议探测内网端口,将解析器当作跳板机。

很多团队在代码审计时发现,自己只是简单地调用了DocumentBuilderFactory.newInstance().newDocumentBuilder(),完全没有意识到这套默认行为在旧JDK下是危险的根源。即便升级到较新JDK,由于部分应用服务器或框架会覆盖工厂属性,默认安全策略也可能失效。因此,不能依赖环境默认值,必须在代码层面对工厂做显式加固。

二、DocumentBuilderFactory关键安全配置项

要阻断XXE,最直接的方式是禁用DTD和外部实体处理。DocumentBuilderFactory提供setFeature方法,可对接底层解析器(如Xerces)的特性开关。最重要的两个特性是http://apache.org/xml/features/disallow-doctype-decl和http://xml.org/sax/features/external-general-entities。前者直接禁止文档中出现DOCTYPE声明,从源头消灭实体定义;后者专门控制是否展开外部通用实体。

除了Feature,还可以通过设置XMLConstants的安全属性来强化。例如XMLConstants.ACCESS_EXTERNAL_DTD和XMLConstants.ACCESS_EXTERNAL_SCHEMA,将它们的值设为空字符串,表示不允许通过DTD或Schema访问任何外部资源。下面是一段典型的加固代码:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import javax.xml.XMLConstants;

public class SafeXmlParser {
    public Document parseXml(byte[] xmlData) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        // 禁止DOCTYPE声明
        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        // 禁用外部通用实体
        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
        // 禁用外部参数实体
        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        // 不展开实体引用
        dbf.setExpandEntityReferences(false);
        // 限制外部DTD和Schema访问
        dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
        DocumentBuilder builder = dbf.newDocumentBuilder();
        return builder.parse(new java.io.ByteArrayInputStream(xmlData));
    }
}

上述代码中,disallow-doctype-decl设为true是最为彻底的方案,因为它让任何携带DOCTYPE的报文直接解析失败,根本不给实体生效的机会。但在某些必须支持合法DTD校验的业务场景下,无法完全禁止DOCTYPE,此时就应保证外部实体相关的两个feature均为false,并配合setExpandEntityReferences(false)避免实体被展开。

三、不同JDK版本下的行为差异与兼容处理

从JDK 7u15、JDK 8u20之后,Oracle官方逐渐将外部实体默认设为不展开,但不同厂商的JDK(如OpenJDK早期构建、Android运行时)表现并不统一。更麻烦的是,像Apache Tomcat或某些ESB产品会在全局系统属性里修改jaxp配置,导致你在本类中做的设置被间接覆盖。因此,在跨环境部署时,建议配合单元测试,用包含外部实体的恶意XML样本验证解析器是否抛异常。

若业务必须使用XML Schema校验而不是DTD,应当优先选用setSchema方式,并同样设置ACCESS_EXTERNAL_SCHEMA为空。此外,勿将DocumentBuilder实例作为静态变量长期复用,因为某些实现并非线程安全,且属性可能在复用中被其他代码篡改。每次解析新建工厂与builder虽然略有开销,但安全边界更清晰。

四、常见配置误区与排查建议

一个典型误区是只设置了external-general-entities为false,却遗漏了external-parameter-entities。参数实体常用于DTD内部被引用的片段,同样可指向外部文件,只堵一半仍会失血。另一个误区是以为调用了setValidating(true)就安全,实际上开启DTD校验反而可能扩大攻击面,除非你明确需要并已禁用外部加载。

排查时可临时在测试环境加入JVM参数-Djaxp.debug=1,观察解析器实际加载的特性列表。同时在网关层对Content-Type为text/xml的请求体做长度与结构扫描,拒绝明显包含<!ENTITY SYSTEM的负载。将解析逻辑封装在统一的安全工具类中,禁止业务代码直接new DocumentBuilderFactory,能从架构上减少遗漏配置的可能。

五、总结性实践清单

综合来看,安全的DocumentBuilderFactory配置应遵循最小权限原则:能不用DTD就不用,必须用时彻底关外部实体。推荐在应用启动阶段打印一次解析器特性,纳入安全基线巡检。下表列出核心开关与推荐值:

配置项推荐值作用
disallow-doctype-decltrue禁止DOCTYPE,根防XXE
external-general-entitiesfalse禁外部通用实体
external-parameter-entitiesfalse禁外部参数实体
expandEntityReferencesfalse不展开实体引用
ACCESS_EXTERNAL_DTD空字符串禁DTD外部访问

把这张清单落地到代码规范里,结合自动化扫描,基本可以消除Java XML解析层面的外部实体风险。安全配置不是一次性的开关,而是需要随依赖升级持续验证的习惯。

DocumentBuilderFactoryXXEXML_security修改时间:2026-08-08 11:06:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。