XXE Attacks in Scala and Play Framework

A couple of times over the last year, I’ve needed to ensure that sites are secure from XML External Entity (XXE) attacks.

What is an XML External Entity (XXE) attack?

An XXE attack uses document type declarations (DTDs) to load file contents from an application server into user-submitted XML whilst parsing. This can then expose data from the server to a malicious user in a response from the server. The OWASP page on this provides more detail on how this works.

An example attacking payload from OWASP’s documentation would be:

<?xml version="1.0" encoding="ISO-8859-1"?>
 <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>

This will attempt to access the contents of the system file /etc/passwd and load it into the <foo> element. If the contents of the XML file is in any way returned to the user, this means the file contents has been read from the system and returned to the malicious user.

OWASP’s recommended solution for this is to disable all document type declarations (DTDs) when configuring an XML parser. It’s therefore important to know what the defaults are in the Play Framework for parsing XML, and what steps can be taken to disable DTDs.

Play Framework 2.3.5 and above

Parsing XML within HTTP Requests

The Play Framework contains a BodyParser helper to ensure that an incoming HTTP request contains valid, well-formed XML within the body of the request.

Examining the source code of Play Framework from 2.3.5 onwards, we can see that the BodyParser helper will parse the XML using a secure implementation of a Java SAXParser XML parser. This secure implementation of the SAXParser will reject any incoming XML that contains a DTD, without parsing the XML first.

So for HTTP requests containing an XML body, we can simply use the parse.xml BodyParser to prevent against XXE attacks.

XmlController

Alternatively, we can use the asXml on the Request body with Scala pattern matching using the following syntax:

AlternateController

Parsing XML from strings and files

But what if I need to parse XML another way, such as parsing a user-submitted XML file?

When manually creating an XML parser, we need to ensure that DTDs are disallowed by the parser. To do this, we can:

    • Create a new instance of SAXParserFactory using SAXParserFactory.newInstance()
    • Configure to the factory to disable namespaces and disallow doctype declarations (as per the OWASP guidance)
    • Create a new SAXParser instance
    • Parse using Scala XML with the new SAXParser instance specified

Parser

Play Framework 2.3.4 and below

The above solution seems neat, easy, and simple to use. However, a little closer research shows that this method within the Play Framework has not always been secure.

In versions on Play Framework below 2.3.5, an insecureĀ parser was used, potentially exposing sites to XXE attacks. This is detailed in the Play documentation here.

Summary

The key to preventing XXE attacks is to ensure a properly configured XML parser, which disallows DTDs so that external files can’t be loaded into the XML.

It’s important to know the defaults settings within whatever language, framework, and version you are using, and Scala and Play Framework are no exception. It’s also vital to drill down into your dependencies, to ensure that you know exactly how your XML is being parsed.

When using the Play Framework BodyParser with Play Framework 2.3.5 or above, the framework will parse using a suitably safe instance of SAXParser. However, if newing up your own parser in code, or using an earlier version of the framework, it’s important to manually configure it to ensure DTDs are not parsed, and your code is not left vulnerable to XXE attacks.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s