org.xml.sax.SAXNotRecognizedException: 无法识别属性"http://javax.xml.XMLConstants/property/accessExternalD



我想在我的项目中防止XXE攻击。这是一个旧的api项目,运行在java7(no-maven)和jboss-as-7服务器上。但在执行过程中,我得到了错误:org.xml.sax.SAXNotRecognizedException:属性'http://javax.xml.XMLConstants/property/accessExternalDTD'无法识别

org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.
15:19:02,845 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at org.apache.xerces.jaxp.validation.ValidatorImpl.setProperty(ValidatorImpl.java:218)
15:19:02,846 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at com.uid.kua.web.KUARestController.authenticateAtAUA(KUARestController.java:118)
15:19:02,847 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
15:19:02,847 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
15:19:02,848 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
15:19:02,849 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at java.lang.reflect.Method.invoke(Method.java:606)

我搜索过它,每个论坛都有不同的含义,说它是一个bug。对于这一例外情况,我没有找到任何相关的解决方案。请帮忙。提前谢谢。

我终于解决了这个问题。我会公布答案,以防这对任何人都有帮助。在通过在线解决方案后,我无法检测到导致上述错误的主要问题。对于xxe预防,我们需要一些定义的属性,如:XMLConstants。ACCESS_EXTERNAL_DDDXML常量。ACCESS_EXTERNAL_SCHEMA

我们需要xercesjaxp-apijars来解析xml,并通过设置上面的一些属性来防止api提供的xxe来解析xml。在JDK7之前,JDK7及更高版本中已经包含了这些功能。因此,我们不需要在项目类路径中导入上述jar。

在我的案例中,我使用的是jboss-as-77.1.Final作为应用程序服务器,它也有自己的xerces jar(org.apache.xerces.)。但java也有自己自己的xeorces和jaxp实现。(com.sun.xerces.)。因此,在部署war时,我们得到了上述错误,因为这两个jar在jboss加载自己的xeerces jar时相互冲突。

解决方案:我们需要通过在jboss.org/apache/xerces/main/modules.xml文件中进行更改来排除jboss-xerces实现。注释行如下所示:

> <module xmlns="urn:jboss:module:1.1" name="org.apache.xerces">    
> <!--
>     <resources>
>         <resource-root path="xercesImpl-2.9.1-jbossas-1.jar"/>
>         Insert resources here
>     </resources>
> -->
>     <dependencies>
>         <module name="javax.api"/>
>     </dependencies>
> 
> </module>

现在部署并运行您的应用程序。快乐的编码。

属性accessExternalDTDaccessExternalSchema似乎是在JAXP1.5中引入的。然而,Java EE 6(甚至仍然是Java EE 8)只附带了JAXP 1.4。

在我的案例中(运行在WildFly 19和AdoptOpenJDK 11上),我能够通过使用Java 9中引入的静态newDefaultInstance()方法来获得JDK的默认实例DocumentBuilderFactorySchemaFactoryewInstance方法,您可以在其中指定类名,即com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.com.sun.org/apache.xerces.internal.jaxp.validation.XMLSchemaFactory.

此解决方案避免了更改JBoss模块。

在我的案例中,在设置道具XMLConstants.ACCESS_EXTERNAL_DTDXMLConstants.ACCESS_EXTERNAL_SCHEMA时,我遇到了类似的问题,但与SAXParser有关。

按照Michael的建议,解决方案是指定SAXParserFactory(我使用的是JDK8)要使用的类名

final SAXParserFactory factory = SAXParserFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", ClassLoader.getSystemClassLoader());

javax.xml通过几个选项加载某些Factory接口的实现。第一个选项是通过系统属性配置默认实现。例如:

javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema = com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory
javax.xml.parsers.DocumentBuilderFactory = com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

第二种选择是使用jaxb.properties文件,您必须将该文件包含在jre或jdk中。如何做到这一点,如下所述:https://docs.oracle.com/javase/tutorial/jaxp/properties/usingProps.html

第三个选项是在META-INF/services中添加一个文件,该文件的名称应该是要为其定义实现的Factory接口,并且该文件应该包含实现的完整包名+类名。例如,您可以添加一个名为javax.xml.parsers.DocumentBuilderFactory的文件,该文件包含com.sun.org.apache.xerces.internal.axp.DocumentBuilderFactoryImpl

第四个选项是选择默认实现。在Wildfly/Jboss的例子中,他们包含了一个只支持JAXP1.4的org.apache.xerces实现。这意味着它将选择此实现,这就是您收到错误的原因。

要了解哪个实现用于您的特定功能,您可以添加系统属性

jaxp.debug = 1

此属性将启用jaxp的调试模式,您将看到以下输出:

JAXP: using thread context class loader (ModuleClassLoader for Module "deployment.css-private-build-1.0-SNAPSHOT.ear.css-private.war" from Service Module Loader) for search
JAXP: Looking up system property 'javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema'
JAXP: The value is 'com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory'
JAXP: createInstance(com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory)
JAXP: loaded com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory from (no code source)
JAXP: factory 'com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory' was found for http://www.w3.org/2001/XMLSchema

因此,在出现错误之前,您将看到JAXP调试日志,然后您应该知道必须为哪个工厂提供实现才能使其工作。

感谢您提供有关xerces的提示。

在Maven Build(mvn-verify)期间运行Java测试时的错误消息如下:

Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

我是这样解决的:

mvn dependency:tree

查找继承xerces:的依赖项

[INFO] +- au.com.dius.pact:consumer:jar:4.2.9:test
[INFO] |  +- au.com.dius.pact.core:model:jar:4.2.9:test
[INFO] |  |  +- org.apache.commons:commons-collections4:jar:4.1:test
[INFO] |  |  +- com.github.mifmif:generex:jar:1.0.2:test
[INFO] |  |  +- javax.mail:mail:jar:1.5.0-b01:test
[INFO] |  |  +- org.apache.tika:tika-core:jar:1.27:test
[INFO] |  |  - io.ktor:ktor-http-jvm:jar:1.3.1:test
[INFO] |  |     +- org.jetbrains.kotlinx:atomicfu:jar:0.14.1:test
[INFO] |  |     +- org.jetbrains.kotlinx:kotlinx-coroutines-core:jar:1.3.3:test
[INFO] |  |     +- org.jetbrains.kotlinx:kotlinx-coroutines-core-common:jar:1.3.3:test
[INFO] |  |     - io.ktor:ktor-utils-jvm:jar:1.3.1:test
[INFO] |  |        - io.ktor:ktor-io-jvm:jar:1.3.1:test
[INFO] |  +- au.com.dius.pact.core:matchers:jar:4.2.9:test
[INFO] |  |  +- xerces:xercesImpl:jar:2.12.0:test

并排除了Maven Pom.xml中相应依赖项中的xerce:

<dependency>
<groupId>au.com.dius.pact</groupId>
<artifactId>consumer</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>aws-java-sdk-s3</artifactId>
<groupId>com.amazonaws</groupId>
</exclusion>                
<exclusion>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
</exclusion>
</exclusions>
</dependency>

在我的案例中,我为Pact测试添加了以下依赖项,但由于以下异常,其他测试突然失败:org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.。我添加的依赖项是:

<dependency>
<groupId>au.com.dius.pact.provider</groupId>
<artifactId>junit5</artifactId>
<scope>test</scope>
</dependency>

为了使其工作,我排除了xerces,如下所示:

<dependency>
<groupId>au.com.dius.pact.provider</groupId>
<artifactId>junit5</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
</exclusion>
</exclusions>
</dependency>

之后一切如常。

好答案-https://stackoverflow.com/a/62404699这只是一个代码示例(使用java11和jboss7.3):

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
DocumentBuilder builder = dbf.newDocumentBuilder();
ByteArrayInputStream input = new ByteArrayInputStream(xmlDocument.getBytes(encoding));
org.w3c.dom.Document doc = builder.parse(input);
DOMBuilder domBuilder = new DOMBuilder();
Document docJdom = domBuilder.build(doc);

我倾向于同意第一条评论的作者(@searchengine27)对已接受答案的看法。修补容器配置看起来不像是一个健壮且可维护的解决方案。

例如,在安装JBoss Wildfly时,我只得到了一个定义上述模块的地方,但在修补JBoss EAP 7.4以在Java 17下工作时,有两个地方,因此更新容器只会破坏工作程序。

还值得一提的是,JBoss提供了javax.api的特定实现(经过测试的安全性等),在决定关闭它之前应该三思而后行

我在第三方库实例化Schemafactory并将accessExternalDTD属性设置为它时遇到了同样的问题

当应用程序在OpenJDK17下的Docker容器中运行,并在JBoss容器中运行时遇到问题时,一切都很好。

我建议的解决方案是为您的程序提供SchemaFactory的实现,该实现利用org.apache.xerces实现,或者JDK中的默认实现(在我的案例中是OpenJDK17)。

我之所以选择后者,是因为我发现它更新并且支持JAXP标准的下一个版本。

这是Jdk17DefaultSchemaFactoryWrapper类的代码:

package my.package.utils.jaxp;
import lombok.experimental.Delegate;
import javax.xml.validation.SchemaFactory;
public class Jdk17DefaultSchemaFactoryWrapper extends SchemaFactory {
@Delegate
SchemaFactory factory = SchemaFactory.newDefaultInstance();
}

相反,SchemaFactory.newDefaultInstance()可能可以使用SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI, "com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", ClassLoader.getSystemClassLoader())来确保JDK中的SchemaFactory得到使用。

并且Jdk17DefaultSchemaFactoryWrapper类必须注册为javax.xml.validation.SchemaFactory。我已经创建了一个文件META-INF/services/javax.xml.validation.SchemaFactory,并将Jdk17DefaultSchemaFactoryWrapper类的完全平衡名称作为其内容。

正如@Appernicus先生在回答这个问题时所提供的那样,也可以采用其他方法来做到这一点。

替代解决方案

另一种解决方案是使用容器提供的实现。

要做到这一点,需要将org.apache.xercesscope: provided的依赖关系添加到它们的POM和以下XMLSchemaFactoryWrapper实现中:

package com.temenos.multifonds.integration.integrationBroker.utils.jaxp;
import lombok.experimental.Delegate;
import org.apache.xerces.jaxp.validation.XMLSchemaFactory;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import javax.xml.XMLConstants;
import javax.xml.validation.SchemaFactory;
public class XMLSchemaFactoryWrapper extends SchemaFactory {
@Delegate(excludes = DelegateExclude.class)
SchemaFactory factory = new XMLSchemaFactory();
@Override
public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
if (XMLConstants.ACCESS_EXTERNAL_DTD.equals(name))
return;
super.setProperty(name, object);
}
private interface DelegateExclude {
void setProperty(String name, Object value);
}
}

正如您可能注意到的,这个解决方案的问题是accessExternalDTD属性实际上被忽略了。

在我的案例中,这不是问题,因为XML模式不使用外部模式,并且该属性是由第三方设置的,以涵盖未来的一些情况。

尽管如此,了解所提供解决方案的优缺点和局限性,应该可以找到适合您特定情况的解决方案。

最新更新