SECURITY INFLUENCERS BLOG

Security influencers provide real-world insight and “in-the-trenches” experiences on topics ranging from application security to DevOps and risk management

START FREE TRIAL

XML External Entity (XXE) Pitfalls With JAXB

The Java XML Binding (JAXB) runtime that ships with OpenJDK 1.8 uses a default configuration that protects against XML external entity (XXE) attacks. Contrast researched this secure default configuration and found that developers should not rely on it to protect their applications from XXE attacks. In this post, we explain why seemingly innocuous changes to the open-source libraries an application uses can affect the default configuration of JAXB, why the default configuration only applies to some JAXB application programming interfaces (APIs), and how Contrast helps development teams better protect applications from XXE attacks. 

What Happens in an XXE Attack

In an XXE attack, the attacker exploits XML’s external entity resolution feature to access sensitive files. Consider a book inventory application that exposes an HTTP API for users to register books defined in XML. An attack may exploit the XXE resolution to register a new book with a title equal to the contents of the /etc/passwd file on the application server.

POST http://example.com:8080/book
Content-Type: application/xml

<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<book>
  <title>&xxe;</title>
</book>
	

When the attacker views the new book they registered, they will see the contents of the application server’s /etc/passwd file.

What Is JAXB

JAXB is a Java technology for binding XML values to Java objects. In the most common use cases of JAXB, users decorate their Java classes with JAXB annotations to configure the mapping between XML and Java objects:

@XmlRootElement(name = "book")
public final class Book {

  @XmlElement private String title;

  public String getTitle() {
    return title;
  }
}

The JAXB Unmarshaller has a handful of unmarshal methods that read a source of XML data and bind its values to a new instance of a Java object. Following is a complete JAXB example of parsing book XML to a new instance of the Book class:

JAXBContext context = JAXBContext.newInstance(Book.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
XMLInputFactory factory = XMLInputFactory.newFactory();
String xml =
    "<?xml version=\"1.0\"?>\n"
        + "<book>\n"
        + "  <title>The Web Application Hacker's Handbook: Discovering and Exploiting Security Flaws</title>\n"
        + "</book>";
XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(xml));
JAXBElement<Book> element = unmarshaller.unmarshal(reader, Book.class);
Book book = element.getValue();
 
When JAXB Is Safe by Default

The JAXB specification does not prescribe how implementations should behave with respect to resolving external entities. Therefore, the default security configuration differs with each JAXB implementation. This implies that application developers need to be aware of the security configuration of their JAXB runtime before they can consider their JAXB code to be secure.

Traditionally, the JAXB implementation an application uses is provided by the Java runtime. This occurs because, until JAXB was removed from the platform in Java SE 11, the Java SE platform shipped with a built-in implementation of JAXB. Different Java runtimes shipped with different JAXB implementations and therefore different security configurations. For example, the JAXB runtime included in OpenJDK 1.8 uses a secure configuration; however, the IBM Java SDK 1.8 does not use a secure configuration.

If you are sure that your application will always use an OpenJDK 1.8-based runtime, then you may be tempted to rely on the secure default behavior. Let’s explore how brittle this default configuration is and the pitfalls that leave your application unexpectedly vulnerable.

Accidentally Replacing the JAXB Runtime

Standard Java XML technologies are defined in specifications, and there are different implementations of those specifications from which developers may choose to build their applications. These implementations are highly pluggable. For example, developers need only to include a new jar in their application to use a different implementation of JAXB.

This flexibility puts developers at risk of accidentally replacing the JAXB runtime in OpenJDK 1.8 with a JAXB implementation that does not use secure defaults. The EclipseLink MOXy project is an example of a JAXB runtime that does not use secure defaults and may be added to an application as a library.

Developers may not even realize their application depends on JAXB: If the application uses a library that depends on a JAXB runtime, then Java build tools like Maven and Gradle will resolve the JAXB runtime as a transitive dependency (unless configured to do otherwise). For example, legacy versions of Jersey included a dependency on a JAXB runtime.

Transitive dependencies are not the only source of rogue JAXB runtimes. When developers deploy their applications to an application server, they may find that the application server provides an alternative JAXB runtime. For example, some versions of WebLogic Server include the EclipseLink MOXy implementation by default, and WebLogic provides a way for applications to opt in to using a GlassFish reference implementation JAXB runtime instead. In both cases, the JAXB runtime in OpenJDK 1.8 is effectively replaced by the runtime provided by WebLogic.

Moving Beyond Java 1.8

Relying on the secure default behavior of the JAXB runtime that is included in OpenJDK 1.8 may work until you need to upgrade your application to use a newer version of Java.

The JAXB API and runtime were included in JavaSE until recently. However, Java SE 11 removed JAXB from the platform. “Missing JAXB” is one of the first breaking changes that developers encounter when upgrading from Java 1.8. The recourse is for developers to add a JAXB runtime to their application as they would any other library. If the application assumes that JAXB uses secure defaults, then developers will need to make sure they include a JAXB runtime that also uses secure defaults, or they will find their application is vulnerable after their Java upgrade.

Accidentally Replacing the SAX Parser

Users who carefully configure their systems to use the OpenJDK 1.8 JAXB runtime with secure defaults may still find themselves using a vulnerable JAXB Unmarshaller due to pitfalls with other pluggable XML technologies. Like JAXB, Java includes other standard XML technologies that may be replaced at runtime with alternative implementations.

One such pluggable XML technology is the SAX parser. The OpenJDK 1.8 JAXB runtime relies on the relatively low-level SAX parser to parse XML data before JAXB binds the XML data to Java objects. The OpenJDK 1.8 JAXB runtime is said to use safe defaults, because the SAXParserFactory, to which JAXB delegates low-level XML parsing, uses secure defaults. When users replace OpenJDK 1.8’s SAX parser with an alternative parser that does not use secure defaults, then their JAXB Unmarshaller becomes vulnerable to XXE attacks.

Apache Xerces is a Java XML technology that includes a SAX parser implementation. Applications that depend on Xerces will use its SAX parser instead of the one that ships with OpenJDK 1.8. Because Xerces is so ubiquitous in the Java ecosystem, there is a strong chance that users inadvertently replace the OpenJDK 1.8’s SAX parser with a Xerces parser.

We reproduced this pitfall with a test web application that relies on the secure default configuration of the OpenJDK 1.8 JAXB runtime. After introducing the xercesImpl-2.8.0.jar dependency to the application, the application was vulnerable to XXE attacks.

Using JAXB Unsafely Despite Safe Defaults

Developers, who are careful enough to avoid the aforementioned pitfalls with pluggable XML technologies, must also take care to use JAXB safely in order to benefit from its secure default configuration.

The JAXB Unmarshaller JavaDoc lists the different sources from which an Unmarshaller may read XML data. Most of these sources are familiar Java IO constructs like java.io.File and java.io.InputStream. The OpenJDK 1.8 JAXB Unmarshaller will use its underlying SAX parser with secure defaults to parse raw XML data from these sources.

On the other hand, some of the XML sources the Unmarshaller supports encapsulate their own XML parsing. When the Unmarshaller reads XML from these sources, its secure default configuration no longer applies. This is why the OWASP XXE Prevention Cheat Sheet says this of JAXB:

Since a javax.xml.bind.Unmarshaller parses XML and does not support any flags for disabling XXE, it’s imperative to parse the untrusted XML through a configurable secure parser first, generate a source object as a result, and pass the source object to the Unmarshaller.
 

The cheat sheet then shows a code snippet that configures a SAXParserFactory with security controls before using the factory to create a SAXSource, which is ultimately passed to the JAXB Unmarshaller.

//Disable XXE
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

//Do unmarshall operation
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(),
                                new InputSource(new StringReader(xml)));
JAXBContext jc = JAXBContext.newInstance(Object.class);
Unmarshaller um = jc.createUnmarshaller();
um.unmarshal(xmlSource);

If the application omits the security controls from this example, then even a JAXB runtime that uses secure defaults (like the one included in OpenJDK 1.8) will be vulnerable to XXE attacks.

The following table shows the JAXB XML sources that must be configured explicitly with security controls to prevent XXE:

Source

Security Controls

javax.xml.transform.stream.DOMSource

Must be applied to the DOM DocumentBuilderFactory that built the DOM DOMSource

javax.xml.transform.stream.SAXSource

Must be applied to SAXParserFactory that built the SAXSource. The Unmarshaller will obtain a SAX XMLReader from the SAXSource

org.w3c.dom.Node

Must be applied to the DOM DocumentBuilderFactory that built the Node

javax.xml.stream.XMLStreamReader

Must be applied to the StAX XMLInputFactory that built the XMLStreamReader

javax.xml.stream.XMLEventReader

Must be applied to the StAX XMLInputFactory that built the XMLEventReader

 
Securing JAXB

JAXB’s secure default configuration is too brittle to rely on in applications that parse untrusted XML. Instead, JAXB users should do as the OWASP XXE Prevention Cheat Sheet recommends and always “parse the untrusted XML through a configurable secure parser first, generate a source object as a result, and pass the source object to the Unmarshaller.

This recommendation requires discipline to make sure it is applied throughout the application. One bad copy/paste from Stack Overflow can leave an application vulnerable to XXE attacks. Fortunately, Contrast Assess and Contrast Protect are remarkably good at identifying insecure uses of JAXB.

Contrast Assess identifies JAXB Unmarshaller instances that do not safely parse XML. Teams that use Contrast Assess in their security testing will see an XXE vulnerability report like the following:

assess-xxe-vulnerability-report

Contrast Assess XXE vulnerability report

While such XXE vulnerabilities remain at large, Contrast Protect identifies and blocks XXE attacks that attempt to exploit these vulnerabilities in production.

protect-xxe-blocked-attacked-report

Contrast Protect XXE blocked attack report
 
Final Recommendations on Protecting Against XXE Attacks

In this post, we examined the secure default configuration for the JAXB runtime in OpenJDK 1.8-based Java distributions. We showed how changes to an application’s XML dependencies can affect the security of JAXB. We also showed how even when JAXB is secure by default, developers still need to exercise discipline to use it safely. Lastly, we recommended that users secure their applications by both applying the guidelines in the OWASP XXE Prevention Cheat Sheet and including Contrast Assess and Contrast Protect in their deployments to detect vulnerabilities and prevent attacks.

blog_jaxb_91520

 

Johnathan Gilday

Johnathan Gilday

Johnathan develops Contrast’s Java agent as a Principal Engineer. From his prior experience with software research and development efforts for the U.S. Department of Defense, he brings expertise in modern software stacks, including mobile platforms, non-relational cloud storage solutions, Java technologies, and cloud automation technologies.

SUBSCRIBE TO THE BLOG