0

I got vulnerabilities flaws from the scan report for Java code, did some research, and found this recommendation to resolve such issues:

Improper Restriction of XML External Entity Reference (CWE ID 611)

This is the code including the fix for the XXE Attack issue:

    public static String convertNodeToString(Node node) {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer;
        try {
            tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
            tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
            transformer = tf.newTransformer();
            // below code to remove XML declaration
            // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(node), new StreamResult(writer));
            String output = writer.getBuffer().toString();
            return output;
        } catch (TransformerException e) {
            e.printStackTrace();
        }

        return null;
    }

The good thing is that JUnit testing was a success, but, when I deployed the code on a running instance, I got this error:

java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD

As per my experience, this is because the running instance uses some dependencies which caused such a conflict and resulted in this error.

Following is part of the stack trace form the console:

java.lang.IllegalArgumentException: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD at org.apache.xalan.processor.TransformerFactoryImpl.setAttribute(TransformerFactoryImpl.java:571)

How I can find which dependency is causing the such error? Is there anything I can do to resolve such an error? I am also suspecting that I missed including a dependency. Please help me solve this issue.

Edit 1:

I did further research and I think this happens because of this reference in the java.exe command used to launch the actual instance:

java.exe -Xbootclasspath/p:../lib/xalan.jar;../lib/xercesImpl.jar;...

Now, I need to find out how I can overcome this issue. I came across some articles proposing to ensure the creation of the factory instance using the correct package. I think the above code ends up using the wrong package.

The question now is how to use java code to ensure using the correct package to create the TransformerFactory instance.

Edit 2:

The first answer helped me make some progress. I found that the classpath of the deployed instance has a reference to org.apache.xalan.processor.TransformerFactoryImpl in xalan.jar which seems it is used by TransformerFactory.newInstance() to create the transformer factory. I think the question is how I can make the needed changes to ensure using the proper class to create the transformer.

Edit 3:

I followed the recommendation here and added this code:

TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);

The error was resolved in the running instance, but, the scan tool is still reporting this vulnerability flaw XXE Attack. According to this article, this happens because an outdated XML processor is present on the classpath (e.g. Xerces, Xalan) which is exactly my case.

I think I came across an article recommending changing some system properties that will indicate the factory to create the transformer instance using the correct class. I am trying to find this article now.

I appreciate your help.

tarekahf
  • 738
  • 1
  • 16
  • 42
  • Do you have a stacktrace with classes and line numbers on the way to this error? – John Williams Mar 22 '23 at 18:03
  • Yes, I just added it. I truly appreciate it if you could help me out with this. I came across a post suggesting using system properties to ensure using the correct instance of the factory, but I cannot find it now. – tarekahf Mar 22 '23 at 19:11
  • @JohnWilliams I updated the question with more details. – tarekahf Mar 23 '23 at 00:14

2 Answers2

1

I had the same problem,this another implementation worked for me:

import com.sun.org.apache.xalan.internal.xsltc.trax.TranformerFactoryImpl;
...
TranformerFactoryImpl tf = new TranformerFactoryImpl();
tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

Edit 1: You also can try to force it:

import javax.xml.transform.TransformerFactory;

TransformFactory tf = new TransformFactory.newInstance(“com.sun.org.apache.xalan.internal.xsltc.trax.TranformerFactoryImpl”, null);
  • I am using JDK jdk1.8.0_351. I added the statement `import com.sun.org.apache.xalan.internal.trax.TranformerFactoryImpl;` and got the error `The import com.sun.org.apache.xalan.internal.trax cannot be resolved`. This means I need to add a specific dependency, correct? Which one? I search all my JARs in the deployed instance for `TranformerFactoryImpl.class` using `cmd>for /R "." %G in (*.jar) do @jar -tvf "%G" | find "TranformerFactoryImpl" > NUL && echo %G` and didn't find it. Please help. – tarekahf Mar 22 '23 at 22:53
  • I think I know what you are getting at! I'll update the question with more details. – tarekahf Mar 22 '23 at 22:53
  • I updated the question with more details. – tarekahf Mar 23 '23 at 00:13
  • It’s suppose to be on jdk(version)/jre/rt.jar – Gabriel S. S. Mar 23 '23 at 12:46
  • I update de answer with another way to force it, and I noticed I forgot a name on the import on the first try, sorry. – Gabriel S. S. Mar 23 '23 at 15:08
  • Yes, thanks a lot. Now I understand what is going on. I found the same answer but using system properties. – tarekahf Mar 23 '23 at 16:39
  • I think it didn't work for me initially because of the wrong spelling of the class you provided. I added my answer. Please reflect on the change to your answer and I will select it as the correct answer. Also, you can't use `TransformFactory tf = new TransformFactory(...)`, you have to use the use `newInstance()` method. – tarekahf Mar 23 '23 at 16:59
  • Done :) I’m happy for help you. – Gabriel S. S. Mar 23 '23 at 23:43
0

Thanks to @Gabriel who helped me find the answer. This is another way to resolve the issue using system properties. The other method is to specify the name of the correct class using the TransformerFactory.newInstance(); method. The correct class is com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl:

tf = TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", NameOfContainerClass.class.getClassLoader());

Below is the final answer which worked for me and the scan report is clean.

private final static String JAVAX_TRANSFORMER_PROP = "javax.xml.transform.TransformerFactory";
private final static String JAVAX_TRANSFORMER_PROP_VAL = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";

public static String convertNodeToString(Node node) throws Exception  {
        TransformerFactory tf=null;
        Transformer transformer;
        String errMsg=null;
        String output=null;
        //Prevent XXE Attack: Ensure using the correct factory class to create TrasformerFactory instance
        //  This will instruct Java to use to version which supports using ACCESS_EXTERNAL_DTD argument.
        // Use:
        //   - com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
        //  instead of:
        //   - org.apache.xalan.processor.TransformerFactoryImpl
        if (System.getProperty(JAVAX_TRANSFORMER_PROP) == null || 
            !System.getProperty(JAVAX_TRANSFORMER_PROP).equals(JAVAX_TRANSFORMER_PROP_VAL))
            System.setProperty(JAVAX_TRANSFORMER_PROP, JAVAX_TRANSFORMER_PROP_VAL);
        try {
            tf = TransformerFactory.newInstance();
        } catch (TransformerFactoryConfigurationError  e) {
            e.printStackTrace();
            errMsg="Error 'TransformerFactoryConfigurationError' in convertNodeToString() while creating 'TransformerFactory' instance: " + e.toString();
        } catch (Exception  e) {
            e.printStackTrace();
            errMsg="Error in convertNodeToString() while creating 'TransformerFactory' instance:: " + e.toString();
        }
        if (errMsg != null)
            throw new Exception(errMsg);
        //Prevent XXE Attack: Set attributes to prevent XXE Attack vulnerabilities.
        try {
            tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
            tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            errMsg = "Error 'IllegalArgumentException' in convertNodeToString() while attempting to prevent XXE Attack: " + e.toString();
        } catch (Exception e) {
            e.printStackTrace();
            errMsg = "Error in convertNodeToString() while attempting to prevent XXE Attack: " + e.toString();
        }
        if (errMsg != null)
            throw new Exception(errMsg);
        //tf.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
        try {
            transformer = tf.newTransformer();
            // below code to remove XML declaration
            // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(node), new StreamResult(writer));
            output = writer.getBuffer().toString();
        } catch (TransformerException e) {
            e.printStackTrace();
            errMsg = "Error 'TransformerException' in convertNodeToString() while converting the node to string: " + e.toString();
        } catch (Exception e) {
            e.printStackTrace();
            errMsg = "Error 'TransformerException' in convertNodeToString() while converting the node to string: " + e.toString();
        }
        if (errMsg != null)
            throw new Exception(errMsg);
        return output;
}

Reference: https://stackoverflow.com/a/50219550/4180447

tarekahf
  • 738
  • 1
  • 16
  • 42