Xalan包在XXE防御中的问题分析与解决方案
一、问题背景
XXE(XML External Entity)攻击是一种常见的XML解析安全漏洞,攻击者通过构造恶意的XML文档,利用外部实体引用功能读取服务器上的敏感文件或发起SSRF攻击。
二、问题发现
在Java中使用TransformerFactory进行XML处理时,通常采用以下安全配置来防御XXE:
TransformerFactory factory = TransformerFactory.newInstance();
// 禁用DTD
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
但当业务代码引入了Xalan包(xalan:xalan:2.7.2)后,上述配置会抛出异常。
三、问题分析
3.1 Java SPI机制的影响
Java的SPI(Service Provider Interface)机制导致TransformerFactory的实现类被Xalan包替换:
-
未引入Xalan包时,默认实现类是JDK自带的:
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl -
引入Xalan包后,实现类变为:
org.apache.xalan.processor.TransformerFactoryImpl
这种变化是因为Xalan包在META-INF/services目录下定义了javax.xml.transform.TransformerFactory文件,指定了自己的实现类。
3.2 Xalan实现类的问题
Xalan的TransformerFactoryImpl存在以下问题:
-
不支持设置
XMLConstants.ACCESS_EXTERNAL_DTD和XMLConstants.ACCESS_EXTERNAL_STYLESHEET属性,设置时会抛出异常 -
虽然支持
XMLConstants.FEATURE_SECURE_PROCESSING属性,但设置为true时不能有效阻止XXE漏洞
测试证明,即使设置了安全处理特性,Xalan仍然会解析外部实体:
<!DOCTYPE any [
<!ELEMENT any ANY>
<!ENTITY some SYSTEM "http://127.0.0.1:3344/nonexist">
]>
<any>&some;</any>
四、解决方案
4.1 指定使用JDK实现类
如果业务不需要Xalan的特殊功能,可以强制使用JDK自带的实现类:
TransformerFactory factory = TransformerFactory.newInstance(
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
TransformerFactory.class.getClassLoader()
);
// 然后可以安全设置防XXE属性
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
4.2 其他注意事项
- Xalan包自2014年后未更新,存在已知安全问题
- Xalan设置不当还可能存在XSLT转换RCE漏洞
- 必须经过充分测试确认使用JDK实现类是否满足业务需求
五、最佳实践建议
- 尽量避免引入Xalan包,除非确实需要其特殊功能
- 如果必须使用Xalan,需要寻找其他方式防御XXE,如:
- 前置XML过滤
- 使用安全策略文件限制
- 定期检查XML处理相关的安全配置
- 新项目建议使用更现代的XML处理库