March 11, 2011

Preventing Entity Expansion Attacks in JAXB

This post will cover how to protect yourself from the entity expansion attack when you are using JAXB.


XML

The XML shown below demonstrates the entity expansion attack.  Entity a contains 10 characters, entity b contains 10 instances of entity a (10^2 characters), entity c contains 10 instances of entity b (10^3 characters), this continues and entity j contains 10^10 or 10 billion characters.

<!DOCTYPE foo [ 
<!ENTITY a "1234567890" > 
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;" > 
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;" > 
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;" > 
<!ENTITY e "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;" > 
<!ENTITY f "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;" > 
<!ENTITY g "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;" > 
<!ENTITY h "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;" > 
<!ENTITY i "&h;&h;&h;&h;&h;&h;&h;&h;&h;&h;" > 
<!ENTITY j "&i;&i;&i;&i;&i;&i;&i;&i;&i;&i;" > 
]> 
<foo>&j;</foo>

Java Model

The following Java class will be used for the domain model in this example.

package blog.entityexpansion;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

@XmlRootElement
public class Foo {

    private String value;

    @XmlValue
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

Java Solution

Java SE 5 has safeguards for this type of attack.  It limits the number of entity expansions to 64,000.  This limit can be changed using the following System property:

-DentityExpansionLimit=100000


Java also provides a standard parser XMLConstants.FEATURE_SECURE_PROCESSING feature that can be enabled to protect from this type of attack.

DOM

DocumentBuilderFactory dbf = 
    DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

SAX

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

JAXB


Since the secure processing feature is enabled by default, the JAXB implementation you are using should already be protected from this type of attack.  However if you want to be 100% sure you can leverage a SAXSource to pass JAXB an XMLReader that is configured to use secure processing:


package blog.entityexpansion;

import java.io.FileReader;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        XMLReader xmlReader = spf.newSAXParser().getXMLReader();
        InputSource inputSource = new InputSource(new FileReader("input.xml"));
        SAXSource source = new SAXSource(xmlReader, inputSource);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Foo foo = (Foo) unmarshaller.unmarshal(source);
        System.out.println(foo.getValue());
    }

}

Output

If the secure processing feature is disabled the example in this post will throw an OutOfMemoryException.  However with the secure processing feature in place you will see the following exception.

[Fatal Error] :1:1: The parser has encountered more than "64,000" entity expansions in this document; this is the limit imposed by the application.
Exception in thread "main" javax.xml.bind.UnmarshalException

2 comments:

  1. "JAXB: Since the secure processing feature is enabled by default..."

    This is not true for all JRE implementation (e.g. IBM). It is recommended to always set the FEATURE_SECURE_PROCESSING.

    ReplyDelete
    Replies
    1. For IBM Java SDK there is a fixpack available at http://www-01.ibm.com/support/docview.wss?uid=swg1IZ77238

      Delete