15

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.

Abhishek Singh
  • 532
  • 1
  • 5
  • 16
  • How do you build the project? Ant? – Ioannis Barakos Oct 14 '19 at 09:57
  • @IoannisBarakos Sorry i didn't mentioned it. Project has default build (java builder) neither ANT nor MAVEN. – Abhishek Singh Oct 14 '19 at 10:01
  • What is the default build? Is there a script that sets a CLASSPATH with the required jars (libs) and then calls javac? I believe the issue is a conflict between your xerces jar and something else. – Ioannis Barakos Oct 14 '19 at 10:06
  • As i mentioned its default Java Builder no scripts. I just added all the jars externally. I rechecked the jars there is no such xerces jar file in my built path. So i am unable to understand what is causing this exception. – Abhishek Singh Oct 14 '19 at 10:09

8 Answers8

20

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.

Abhishek Singh
  • 532
  • 1
  • 5
  • 16
  • 2
    Modifying the AS modules is not the answer. -1. It just means your deployments are using the wrong dependencies. You wouldn't remove all the milk in the entire world because you're lactose intolerant, would you? – searchengine27 Aug 31 '22 at 14:21
  • I tend to agree with the author of the comment above. I elaborated on my opinion in [another answer](https://stackoverflow.com/a/74208524/31090) to this question. – Ed Gomoliako Oct 26 '22 at 13:26
12

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.

Michael
  • 131
  • 1
  • 3
  • 5
    This worked, but I had to pass the system's class loader as an argument also: `DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl", ClassLoader.getSystemClassLoader());` – Thiago Chaves Oct 14 '20 at 14:32
  • @ThiagoChaves Do you happen to know why it has to be the system class loader? I've got the same issue and need to pass a class loader to the method, but although system class loader seems to work, I am not sure why it does and `class.getClassLoader()` does not. – JSamir Apr 15 '21 at 21:37
  • @JSamir you need to do reading on how JBoss classloader architecture works. That is a long explanation that no one here is going to do for you because there is lots of online documentation from JBoss itself that explains that answer. – searchengine27 Aug 31 '22 at 14:24
2

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());
2

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.

Appernicus
  • 434
  • 1
  • 4
  • 12
  • 1
    This is a good answer describing the underline mechanisms of how the relevant module works. It helps to figure out the appropriate solution for a specific case. Thank you! – Ed Gomoliako Oct 26 '22 at 12:49
1

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>
snukone
  • 312
  • 3
  • 10
1

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.

times29
  • 2,782
  • 2
  • 21
  • 40
0

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);
msanford
  • 11,803
  • 11
  • 66
  • 93
-1

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.

Ed Gomoliako
  • 991
  • 1
  • 8
  • 18
  • Sorry, if I'm reading correctly, this answer provides two different approaches that explicitly _don't_ support the `accessExternalDTD` property that OP wants to enable? This isn't a valid answer imo. – Parker Kemp Jul 13 '23 at 15:06
  • @ParkerKemp the alternative approach doesn't, but the primary one does. Probably it is worth to re-read. – Ed Gomoliako Jul 26 '23 at 10:27