XML injection (XXE) - Java

XML injection (XXE) - Java

Need

Prevention of XML injection attacks

Context

  • Usage of Java 8 for developing applications with enhanced features and performance improvements
  • Usage of javax.servlet-api for Java Servlet development
  • Usage of javax.xml.parsers for XML parsing and processing

Description

Non compliant code

        import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class XMLInjectionServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            dBuilder.parse(request.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
        
        

The above code represents a servlet in a Java backend application that accepts XML data in the POST request body and parses it into a Document object. This is done using the DocumentBuilderFactory and DocumentBuilder classes provided by the javax.xml.parsers package.

The vulnerability lies in the doPost method, where the XML data from the request is directly parsed without any checks for potentially malicious content. This means that if an attacker sends a specially crafted XML payload, they could perform an XML External Entity (XXE) injection attack.

In an XXE injection attack, the attacker defines an external entity with a URI in the DOCTYPE of the XML data. When the XML data is parsed, the parser can be tricked into dereferencing the URI and incorporating the data it points to into the parsed XML document. This could potentially allow the attacker to read sensitive data from the server, perform a Denial of Service (DoS) attack, or even execute arbitrary code.

In the case of the above code, an attacker could send a POST request with XML data containing an external entity that points to a sensitive file on the server. When the dBuilder.parse(request.getInputStream()) line is executed, the contents of the sensitive file could be incorporated into the parsed XML document and returned to the attacker.

Steps

  • Validate and sanitize user input: Ensure that any user input that is used to construct or manipulate XML is properly validated and sanitized. This includes input from HTTP requests, user-controlled files, or any other external sources.
  • Disable external entity resolution: Disable the ability to resolve external entities in XML parsing. This can be done by setting the 'FEATURE_SECURE_PROCESSING' feature to true in the XML parser configuration.
  • Use a whitelist approach: Only allow specific XML elements, attributes, and entities that are necessary for the application's functionality. Reject any other input that does not adhere to the whitelist.
  • Implement input validation: Validate the structure and content of XML input to ensure it conforms to the expected format. This can be done using XML schema validation or custom validation logic.
  • Limit XML entity expansion: Set limits on the number of entity expansions allowed during XML parsing to prevent denial-of-service attacks. This can be done by setting the 'ENTITY_EXPANSION_LIMIT' property in the XML parser configuration.
  • Keep XML parsers up to date: Ensure that the XML parser library used in the application is kept up to date with the latest security patches and updates.
  • Implement access controls: Restrict access to sensitive XML files or resources to prevent unauthorized access or manipulation.
  • Implement secure coding practices: Follow secure coding practices to minimize the risk of introducing vulnerabilities in the XML parsing code. This includes input validation, output encoding, and error handling.
  • Regular security testing: Conduct regular security testing, including penetration testing and code reviews, to identify and address any potential vulnerabilities in the XML parsing code.

Compliant code

        import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

public class XMLInjectionServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            dbFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            dbFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            dbFactory.setXIncludeAware(false);
            dbFactory.setExpandEntityReferences(false);
            
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            dBuilder.parse(request.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
        
        

The above code is a fixed version of the previously vulnerable XML parsing code. The vulnerability was XML External Entity (XXE) Injection, which could allow an attacker to inject malicious XML code into the application's requests, leading to data exfiltration or remote command execution.

The fix involves several steps:

1. Disable external entity resolution: The DocumentBuilderFactory instance is configured to disallow DOCTYPE declaration ( disallow-doctype-decl) and to disable resolution of external general and parameter entities. This is done by setting the corresponding features to false.

2. Disable XInclude: The setXIncludeAware(false) method call disables XInclude processing in the XML parser, which could be used to include external XML entities.

3. Disable entity reference expansion: The setExpandEntityReferences(false) method call disables the expansion of entity references in the XML parser.

These changes prevent the XML parser from processing external entities and thus mitigate the XXE vulnerability. However, this is just one part of the solution. It's also important to validate and sanitize user input, use a whitelist approach for allowed XML elements, implement input validation, limit XML entity expansion, keep XML parsers up to date, implement access controls, follow secure coding practices, and conduct regular security testing.

References