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
"JAXB: Since the secure processing feature is enabled by default..."
ReplyDeleteThis is not true for all JRE implementation (e.g. IBM). It is recommended to always set the FEATURE_SECURE_PROCESSING.
For IBM Java SDK there is a fixpack available at http://www-01.ibm.com/support/docview.wss?uid=swg1IZ77238
Delete