是否可以避免使用 xalan TransformerFactory?
Posted
技术标签:
【中文标题】是否可以避免使用 xalan TransformerFactory?【英文标题】:Is it possible to avoid using xalan TransformerFactory? 【发布时间】:2018-10-04 15:51:03 【问题描述】:我有以下代码:
final TransformerFactory factory = TransformerFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
第二行在现代 JDK(我试过 1.8)中运行良好,默认为 TransformerFactory
。但是,当我将 xalan
(版本 2.7.2,最新版本)添加到类路径时,我在第二行得到以下信息:
Exception in thread "main" java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD
at org.apache.xalan.processor.TransformerFactoryImpl.setAttribute(TransformerFactoryImpl.java:571)
at Main.main(Main.java:11)
我猜这是因为xalan 的TransformerFactory
不支持这个属性。 Xalan 的实现通过ServiceLoader
机制获取:在 xalan jar 中的services/javax.xml.transform.TransfomerFactory
中指定。
可以使用javax.xml.transform.TransformerFactory
系统属性或$JRE/lib/jaxp.properties
文件覆盖TransformerFactory
实现,或直接在代码中传递类名。但要做到这一点,我必须提供一个具体的类名。现在是com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
,但是在系统属性中硬编码它有点吓人,因为在JDK升级时他们可以很容易地更改类名,我们只会得到一个运行时错误。
有没有办法指示TransformerFactory.newInstance()
忽略 xalan 提供的实现?或者告诉它“只使用系统默认值”。
附:我不能只从类路径中删除xalan
,因为我们使用的许多其他库都依赖于它。
【问题讨论】:
您是否要禁用此功能?如果是这样,请看这里:***.com/questions/27128578/… @trappski 是的,我正在尝试禁用外部 DTD 处理,所以我的问题看起来像是 X/Y 问题。但是factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
不会阻止 Xalan 访问外部 DTD:当我使用外部 DTD 链接(http 链接)提供 XML 时,Xalan 会尝试加载该 DTD 并获得 ConnectException
。
【参考方案1】:
我在这里唯一能做到的就是硬编码 JDK 默认工厂并使用正常的发现过程作为后备:
TransformerFactory factory;
try
//the open jdk implementation allows the disabling of the feature used for XXE
factory = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", SecureXmlFactories.class.getClassLoader());
catch (Exception | TransformerFactoryConfigurationError e)
//this part uses the default implementation of in xalan 2.7.2
LOGGER.error("Cannot load default TransformerFactory, le's try the usual way", e);
//not advisable if you dont want your application to be vulnerable. If needed you can put null here.
factory = TransformerFactory.newInstance();
然后在try/catch
下配置
// this works everywhere, but it does not disable accessing
// external DTDs... still enabling it just in case
try
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
catch (TransformerConfigurationException e)
LOGGER.error("Cannot enable secure processing", e);
// this does not work in Xalan 2.7.2
try
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
catch (Exception e)
LOGGER.error("Cannot disable external DTD access", e);
// this does not work in Xalan 2.7.2
try
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
catch (Exception e)
LOGGER.error("Cannot disable external stylesheet access", e);
并监视日志以查看默认 JDK 工厂类名称是否/何时更改。
【讨论】:
请注意 catch 块factory = TransformerFactory.newInstance();
中的实现。它不是 XXE 安全的,如果受到攻击,此逻辑将失败。
能否告诉我们使用 SecureXmlFactories.class 文件的 jar 文件名。
@ParameshKorrakuti SecureXmlFactories
是包含作为建议解决方案显示的代码的类的名称。您可以只使用此处显示的 sn-ps,类名并不重要。【参考方案2】:
定义要加载哪个 TransformerFactory 实现的另一种方法是设置 javax.xml.transform.TransformerFactory
系统属性 (docs)。
在 Ant 中,你会在你的目标中做这样的事情:
<jvmarg value="-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"/>
在上面的示例中,我将 OpenJDK8 中的设置为默认设置
【讨论】:
【参考方案3】:这不适用于 JAVA9 及更高版本。像这样将 FactoryClass 和类加载器传递给 newInstance
final TransformerFactory transformerFactory = TransformerFactory.newInstance( "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl",
CLASS_NAME.class.getClassLoader());
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
【讨论】:
以上是关于是否可以避免使用 xalan TransformerFactory?的主要内容,如果未能解决你的问题,请参考以下文章
DETR(DEtection TRansforme)调试记录
DETR(DEtection TRansforme)调试记录
Java 中是不是有比 Xalan/Xerces 更快的 XML 解析器 [关闭]
Transforme结构:位置编码 | Transformer Architecture: The Positional Encoding