java中禁用dtd解析防止xxe需显式设置disallow-doctype-decl等特征,spring boot须重写documentbuilderfactory bean,第三方库需单独加固并验证payload。

Java中禁用DTD解析防止XXE
默认的DocumentBuilder和SAXParser会加载外部DTD,这是XML注入(XXE)的根本入口。必须显式关闭DTD加载,不能只靠过滤输入。
- 对
DocumentBuilderFactory:调用setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)—— 这是最关键一步,仅设setValidating(false)无效 - 对
SAXParserFactory:同样需启用http://apache.org/xml/features/disallow-doctype-decl,并额外设置http://xml.org/sax/features/external-general-entities和http://xml.org/sax/features/external-parameter-entities为false - 使用
TransformerFactory处理XML时也要禁用:调用setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true),它会限制XSLT扩展但不自动禁DTD
Spring Boot项目里XML解析器统一加固
Spring默认用Jaxb2RootElementHttpMessageConverter或MappingJackson2XmlHttpMessageConverter,但底层仍走JDK原生解析器。不改配置,加再多Filter都没用。
- 在
@Configuration类中重写DocumentBuilderFactoryBean,强制注入已禁DTD的实例 - 若用
RestTemplate接收XML,确保其HttpMessageConverter底层使用的DocumentBuilder来自加固后的工厂 - 检查依赖:某些老版本
commons-digester或spring-oxm会绕过你的配置,升级到spring-oxm 5.3.30+或6.1.0+更稳妥
测试XXE是否真被堵死
光看代码没用,得用典型payload验证。常见错误是只测了 ]>,但漏了其他变体。
- 必测三类payload:
SYSTEM读文件、ENTITY引用内部声明、parameter entity触发二次解析(如%remote;) - 本地调试时,把
DocumentBuilder.parse()包装一层try-catch,捕获SAXParseException——如果抛出“DOCTYPE is disallowed”说明生效;若静默返回空数据或报FileNotFoundException,说明没禁住 - 注意IDEA或JUnit运行时可能用不同JDK版本,生产环境用OpenJDK 17+时,
disallow-doctype-decl才完全可靠;Java 8u191之前存在绕过漏洞
第三方库自带XML解析怎么办
像Apache POI读取.docx、Log4j解析XML格式日志、甚至Shiro的INI配置加载,都可能悄悄调用DocumentBuilder。它们不会读你的全局配置。
立即学习“Java免费学习笔记(深入)”;
- 查Maven依赖树:
mvn dependency:tree | grep xml,重点盯poi-ooxml、log4j-core、xstream(已知高危) -
XStream必须升级到1.4.19+,并显式调用new XStream().denyTypes(new Class[]{...}),不能只靠addPermission - 对无法升级的库(如老版
poi-3.17),在JVM启动参数加-Djavax.xml.parsers.DocumentBuilderFactory=xxx.SecureDocumentBuilderFactory强行替换工厂类
最易忽略的是:同一应用里多个XML解析路径(HTTP body、文件上传、定时任务读配置),只要有一处漏加固,整个防护就失效。别信“我只用Jackson XML,肯定安全”——它底层仍可能fallback到JDK原生解析器。









