Skip to main content

Is JAXB susceptible to DTD entity expansion attack?

7 replies [Last post]
baker2g
Offline
Joined: 2010-01-06

I was doing a little research on JAXB related to security and DoS attacks. I see that JAXB supports DTD. Does that mean that JAXB is vulnerable to entity expansion attacks?

For instance, if I attempt to unmarshall the following, what would happen?

<?xml version='1.0' encoding='iso-8859-1'?>

...

]>
&x0;

Is there any way to configure JAXB to not accept DTDs?

Message was edited by: baker2g

Message was edited by: baker2g

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
blaise_doughan
Offline
Joined: 2003-09-30

You can create a SAXSource in the following way and have JAXB unmarshal that:

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
SAXParser sp = spf.newSAXParser();
XMLReader xmlReader = sp.getXMLReader();
SAXSource saxSource = new SAXSource(xmlReader, inputSource);
ramapulavarthi
Offline
Joined: 2004-06-01

XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.SUPPORT_DTD,false);
unmarshaller.unmarshal(xif.createXMLStreamReader(inputstream,encoding)) ....

ramapulavarthi
Offline
Joined: 2004-06-01

If you using JAXB for Web Services via JAX-WS, by default JAX-WS does not support DTDs. So, I believe, you should be safe aganist expansion attacks with jax-ws.

baker2g
Offline
Joined: 2010-01-06

That is my understanding as well, however, in my scenario I am unmarshalling the XML outside of the context of JAX-WS. I am using JAXB to unmarshal XML content and bind it to a set of Java classes so that I can easily process the information from within my java code. This means that I do not benefit from any of the safety that JAX-WS may provide.

If you're curious, I am able to crash my application by submitting malicious XML similar to what is mentioned in my original post. So I guess that answers the first part of my question. Now I need to know how to fix it.

Please chime in if you have any ideas.

Thanks

ramapulavarthi
Offline
Joined: 2004-06-01
baker2g
Offline
Joined: 2010-01-06

Here is the code I have.

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

...

JAXBContext jc = JAXBContext.newInstance("com.namespace.blah.blah");
Unmarshaller unmarshaller= jc.createUnmarshaller();

//This throws an exception
//unmarshaller.setProperty("javax.xml.stream.supportDTD", false);

SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

//This throws an exception
//factory.setProperty("javax.xml.stream.supportDTD", false);

URL xsdLocation = MetrixEventManagerServiceEndpoint.class.getClassLoader().getResource("xsds/payloadDefinition.xsd");
File xsd = new File(xsdLocation.getPath());
Schema validationSchema;
validationSchema = factory.newSchema(xsd);
unmarshaller.setSchema(validationSchema);

...

//This will hang when the payload is an XML document using a DTD with
//an entity expansion attack
//FYI: the payload variable is a String that contains the XML
Object boundObject = unmarshaller.unmarshal(new InputStreamReader(new ByteArrayInputStream(payload.getBytes()), Charset.forName("UTF-8").newDecoder()));

There seems to be only two places where a "setProperty" method is available and neither of them support the "javax.xml.stream.supportDTD" property. Looking at the documentation for the Unmarshaller interface (http://java.sun.com/webservices/docs/1.6/api/javax/xml/bind/Unmarshaller...), it says that implementors are not required to support any properties, so I suppose that it is not surprising that an attempt to set this property is throwing an exception. I am unable to find documentation on supported properties for the SchemaFactory interface.

Perhaps there is something I am missing, or another way to go about this?

I was considering searching the payload string before I process it and rejecting any payload that even contains "

Again, I appreciate the time you are taking to help me out on this issue.

Thanks

baker2g
Offline
Joined: 2010-01-06

WAIT A MINUTE!!!

I was looking more closely at your post and realized that I should have tried a different approach. Instead of using a InputStreamReader to read in the XML document, I am now using an XMLStreamReader obtained from the XMLInputFactory, where the "javax.xml.stream.supportDTD" property is supported. That portion of my code now looks like this:

XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty("javax.xml.stream.supportDTD", false);

//Deserialize the raw paylaod
Object boundObject = unmarshaller.unmarshal(factory.createXMLStreamReader(new ByteArrayInputStream(payload.getBytes()), "UTF-8"));

I have a unit test that reproduces the entity expansion attack and now when I run it it throws an exception (rather than crashing my app):

javax.xml.bind.UnmarshalException
- with linked exception:
[com.ctc.wstx.exc.WstxParsingException: Undeclared general entity "x0"

This tells me that the XMLStreamReader ignored the DTD and then gave up when it found an entity that it did not recognize. This is exactly the behavior that I want!

Thanks again for your help.