Reputation: 625
I want to prevent a XXE attack in my project. It's old api project which runs on java 7 (no maven) and jboss-as-7 server. But during the execution i get the error: org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.
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)
I have searched about it and every forum has some different meaning to it saying it's a bug. I have not found any relevant solution for this exception. Please help. Thanks in advance.
Upvotes: 17
Views: 46400
Reputation: 3373
In my case I added the following dependency for Pact tests and suddenly other tests failed due to the following exception: org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.
. The dependency I added was this:
<dependency>
<groupId>au.com.dius.pact.provider</groupId>
<artifactId>junit5</artifactId>
<scope>test</scope>
</dependency>
To make it work I excluded xerces
as follows:
<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>
After that everything worked as before.
Upvotes: 1
Reputation: 1038
I tend to agree with the opinion of the author (@searchengine27) of the first comment on the accepted answer. Patching container configuration doesn't look like a robust and maintainable solution.
For instance, with the JBoss Wildfly installation, I got only one place where the mentioned module was defined, but with the JBoss EAP 7.4 patched to work under Java 17 there were two places, thus having the container updated just ruined the working program.
It's also worth mentioning that JBoss is provided with the particular implementation of javax.api
on purpose (tested security, etc.) and one should think twice before deciding to turn it off.
I encountered the same problem with a third-party library instantiating Schemafactory
and setting the accessExternalDTD
property to it.
Everything worked well when the application was running in a Docker container under OpenJDK17 and got into trouble running inside the JBoss container.
The solution I propose is to provide with your program an implementation of SchemaFactory
that leverages either org.apache.xerces
implementation, or the default one from the JDK (OpenJDK17 in my case).
I've chosen the latter because I found it newer and supports the next version of the JAXP standard.
Here is the code of the Jdk17DefaultSchemaFactoryWrapper
class:
package my.package.utils.jaxp;
import lombok.experimental.Delegate;
import javax.xml.validation.SchemaFactory;
public class Jdk17DefaultSchemaFactoryWrapper extends SchemaFactory {
@Delegate
SchemaFactory factory = SchemaFactory.newDefaultInstance();
}
Instead SchemaFactory.newDefaultInstance()
probably SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI, "com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", ClassLoader.getSystemClassLoader())
could be used to make sure that the SchemaFactory
from the JDK gets used.
And the Jdk17DefaultSchemaFactoryWrapper
class has to be registered as javax.xml.validation.SchemaFactory
. I've done it via creating a file META-INF/services/javax.xml.validation.SchemaFactory
and putting the full quilified name of the Jdk17DefaultSchemaFactoryWrapper
class as its contents.
As Mr. @Appernicus provided in his answer to this question, other ways could be approached to get done the same.
Alternative Solution
An alternative solution would be to use the implementation provided by the container.
To do that, one would need to add the org.apache.xerces
dependency with the scope: provided
to their POM and the following XMLSchemaFactoryWrapper
implementation:
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);
}
}
As you might notice, the problem with this solution is that the accessExternalDTD
property actually gets ignored.
In my case, it wasn't a problem because XML schemas didn't use external schemas and the property was set by the third party to cover some future cases.
Though, knowing pros and cons and limitations of the provided solutions it should be possible to find the one that suits your particular case.
Upvotes: -1
Reputation: 464
javax.xml loads the implementation of certain Factory interfaces by going through a couple of options. First option is to configure a default implementation through a system property. For example:
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
The second option is to use the jaxb.properties file which you have to include in your jre or jdk how you can do do that is described here: https://docs.oracle.com/javase/tutorial/jaxp/properties/usingProps.html
The third option is to add a file in META-INF/services of which the name should be the Factory interface that you want to define the implementation for and the file should contain the full package name + class name of the implementation. For example, you can add a file called javax.xml.parsers.DocumentBuilderFactory containing com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
The fourth option is to select the default implementation. In the case of Wildfly/Jboss they have included an org.apache.xerces implementation which only support JAXP 1.4. This means that it will select this implementation and that's why you get the error.
To find out which implementation is used for your specific function you can add a system property
jaxp.debug = 1
This property will enable debug mode for jaxp and you will see the following output:
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
So before your error you will see the JAXP debug logging and then you should know which factory you have to provide an implementation for to get it to work.
Upvotes: 4
Reputation: 332
Thanks for Hint regarding xerces.
My Error-Message when running Java tests during a Maven Build (mvn verify) look like this:
Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.
I solved it this way:
mvn dependency:tree
Finding the Dependency which is inheriting 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
And excluded xerces in the corresponding Dependency in the Maven Pom.xml:
<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>
Upvotes: 1
Reputation: 21
In my case, I had a similar issue, but related to the SAXParser
, when setting the props: XMLConstants.ACCESS_EXTERNAL_DTD
and XMLConstants.ACCESS_EXTERNAL_SCHEMA
.
The solution following Michael's suggestion was to specify the classname to be used by the SAXParserFactory
(I am using JDK 8)
final SAXParserFactory factory = SAXParserFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", ClassLoader.getSystemClassLoader());
Upvotes: 2
Reputation: 11
good answer - https://stackoverflow.com/a/62404699 It's just example of a code (work with java 11 and jboss 7.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);
Upvotes: 0
Reputation: 161
It seems that the attributes accessExternalDTD and accessExternalSchema were introduced in JAXP 1.5. However, Java EE 6 (and even still Java EE 8) only comes with JAXP 1.4.
In my case (running on WildFly 19 and AdoptOpenJDK 11) I was able to obtain the JDK's default instances of DocumentBuilderFactory and SchemaFactory by using their static newDefaultInstance() method which was introduced in Java 9. In Java 8 both classes also have a newInstance method where you can specify the class name, i.e. com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl and com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.
This solution avoids changing the JBoss modules.
Upvotes: 14
Reputation: 625
Finally i resolved it. I am posting the answer in case this helps anyone. After going through online solutions i was unable to detect the main issue which was causing the above error. For xxe prevention we need some defined properties like: XMLConstants.ACCESS_EXTERNAL_DTD XMLConstants.ACCESS_EXTERNAL_SCHEMA
We need xerces and jaxp-api jars to pasrse xml and prevent xxe provided by the api's to resolve the xml by setting some above properties. Prior to JDK 7 these are already included in JDK 7 and above. So we don't need to import above jars in our project classpath.
In my case i was using jboss-as-7.1.1.Final as application server which also has it's own xerces jar (org.apache.xerces.). But java also comes with it's own xerces and jaxp implementation (com.sun.xerces.). So while deploying the war we get the above error as both these jars conflicts with each other where jboss loads it's own xerces jars.
Solution: We need to exclude the jboss xerces implementation by making changes in jboss/org/apache/xerces/main/modules.xml file. Comment out the lines as shown below:
> <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>
Now deploy and run your application. Happy coding.
Upvotes: 22