是否可以避免使用 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

Xalan XSLT - 内存堆空间不足

将 Xalan 与 Saxon 一起使用