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.
–
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);
–
–
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
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.