Java XML Tutorial

How to prevent XML external entity attack (XXE attack)

This article talks about XML external entity attack (XXE attack) and how to prevent XXE from a list of the popular XML parsers like DOM, SAX, JDOM, etc.

1. What is XML external entity attack (XXE attack)

The XML external entity attack (also known as XXE attack) is an attack against an application that parses XML data that containing the external entities. The XML parser will load the external entities’ content from the server file system or network, which may lead to arbitrary file disclosures or server-side request forgery (SSRF) vulnerabilities.

Note
See CWE-611

2. XXE attack example

This example shows how to use the XXE attack to retrieve the content of the files on the server.

2.1 An application parses the below XML file, gets the staff id and displays the staff’s name.

staff.xml

  <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>1001</staffId>
  </company>

Output


  <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>Yong Mook Kim</staffId>
  </company>

2.2 Now, the attacker manipulates the incoming XML file’s content, replacing the XML data with a malicious external entity that references the server’s file /etc/passwd.

staff.xml

  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
  <company>
      <staffId>&xxe;</staffId>
  </company>

When the XML parser parses the above malicious external entity, it will include the file /etc/passwd content at the corresponding position. For a weakly configured XML parser (typically, it is the default XML parser), the &xxe; entity will be replaced by the contents of the file /etc/passwd.

Output


  <?xml version="1.0" encoding="utf-8"?>
  <company>
    <staffId>nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
    root:*:0:0:System Administrator:/var/root:/bin/sh
    daemon:*:1:1:System Services:/var/root:/usr/bin/false
    </staffId>
  </company>

Here’s a SAX XML parser that is vulnerable to XXE attack.

ReadXmlSaxParserXXE.java

package com.mkyong.xml.sax;

import com.mkyong.xml.sax.handler.PrintAllHandlerSax;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;

public class ReadXmlSaxParserXXE {

  private static final String FILENAME = "src/main/resources/staff.xml";

  public static void main(String[] args) {

      SAXParserFactory factory = SAXParserFactory.newInstance();

      try {

          // XXE attack
          SAXParser saxParser = factory.newSAXParser();

          PrintAllHandlerSax handler = new PrintAllHandlerSax();

          saxParser.parse(FILENAME, handler);

      } catch (ParserConfigurationException | SAXException | IOException e) {
          e.printStackTrace();
      }

  }

}

3. How to prevent XXE attack in SAX parser

We can use setFeature for the SAX parser to disable the DOCTYPE declaration completely.


  SAXParserFactory factory = SAXParserFactory.newInstance();

  try {

      // https://rules.sonarsource.com/java/RSPEC-2755
      // prevent XXE, completely disable DOCTYPE declaration:
      factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

      SAXParser saxParser = factory.newSAXParser();

      PrintAllHandlerSax handler = new PrintAllHandlerSax();

      saxParser.parse(FILENAME, handler);

  } catch (ParserConfigurationException | SAXException | IOException e) {
      e.printStackTrace();
  }

Now, if the SAX parser parses any external entities, it will prompt an error:

Output

Terminal

org.xml.sax.SAXParseException; staffId: file:///Users/yongmookkim/projects/core-java/java-xml/src/main/resources/staff-xxe.xml;
 lineNumber: 2; columnNumber: 10; DOCTYPE is disallowed
 when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.

4. Sonar Rule to prevent XXE attack in XML parser

Review this Sonar rule – XML parsers should not be vulnerable to XXE attacks for a complete solution for a list of the popular XML parsers.

For DOM Parser


  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or completely disable external entities declarations:
  factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
  factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
  // or prohibit the use of all protocols by external entities:
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
  // or disable entity expansion but keep in mind that this doesn't prevent fetching external entities
  // and this solution is not correct for OpenJDK < 13 due to a bug: https://bugs.openjdk.java.net/browse/JDK-8206132
  factory.setExpandEntityReferences(false);

For SAX Parser


  SAXParserFactory factory = SAXParserFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or completely disable external entities declarations:
  factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
  factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
  // or prohibit the use of all protocols by external entities:
  SAXParser parser = factory.newSAXParser(); // Noncompliant
  parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

XMLInput, Transformer, Schema


  XMLInputFactory factory = XMLInputFactory.newInstance();
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
  // or completely disable external entities declarations:
  factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
  // or prohibit the use of all protocols by external entities:
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

  TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
  // to be compliant, prohibit the use of all protocols by external entities:
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

  SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  // to be compliant, completely disable DOCTYPE declaration:
  factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  // or prohibit the use of all protocols by external entities:
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");  

For Dom4j library:


  SAXReader xmlReader = new SAXReader();
  xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

For JDOM library


  SAXBuilder builder = new SAXBuilder();
  builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
  builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

5. Download Source Code

$ git clone https://github.com/mkyong/core-java

$ cd java-xml

$ cd src/main/java/com/mkyong/xml/sax/

6. References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
3 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Goutam
7 months ago

Please Help how we can prevent xxe on a soap request, as per my knowledge soap request are directly coming to the service class , where and what logic we need to add to prevent XXE.

Aaisha vats
1 year ago

Thank you so much for the brief information about XML. This is really very impressive when I read out this blog it is really informative.

hichem
1 year ago
Reply to  Aaisha vats

Hi

Thank you for these details on how to fix XXE on different parsers.

While testing XXE attack fix for SAXBuilder from ReadXmlJDomParser sample, I got this exception. see below.

Any clue please?

SAXBuilder builder = new SAXBuilder();
 builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, “”);
 builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, “”);

org.jdom2.JDOMException: http://javax.xml.XMLConstants/property/accessExternalDTD property not recognized for SAX driver oracle.xml.parser.v2.SAXParser
at org.jdom2.input.SAXBuilder.internalSetProperty(SAXBuilder.java:1044)
at org.jdom2.input.SAXBuilder.configureParser(SAXBuilder.java:981)
at org.jdom2.input.SAXBuilder.buildEngine(SAXBuilder.java:856)
at org.jdom2.input.SAXBuilder.getEngine(SAXBuilder.java:904)
at org.jdom2.input.SAXBuilder.build(SAXBuilder.java:1116)
at parsers.ReadXmlJDomParser.main(ReadXmlJDomParser.java:45)