Can JAXB be configured to prevent entity expansion attacks?
Normally when parsing XML in java, it's possible to avoid falling victim to entity expansion attacks by using
dbf.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);开发者_运维问答
Where dbf is a DocumentBuilderFactory used to create DocumentBuilders for XML parsing.
However, suppose I am unmarshalling some XML using JAXB, e.g. like this:
final JAXBContext context = JAXBContext.newInstance(MyClass.class);
final Unmarshaller unmarshaller = context.createUnmarshaller();
final MyClass result = (MyClass) unmarshaller.unmarshal(input);
How can I configure JAXB to use FEATURE_SECURE_PROCESSING on the underlying XML parser?
Googling for answers brings up the following as the best result: http://forums.java.net/node/699983
However, I don't want to have to bring in implementations of XMLStreamFactory and the like just to make entity expansion configurable. Is there a way to solve this problem using just the JAXB API?
Java SE 5 limits the number of entity expansions to 64,000:
- http://download.oracle.com/javase/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html#JAXP_security
I would expect that all JAXB implementations would leave this default protection in place. However if you want to be 100% sure 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);
For more information see:
- http://bdoughan.blogspot.com/2011/03/preventing-entity-expansion-attacks-in.html
I was using code very similar to that in Blaise's answer and recently discovered it had a subtle issue. The XMLReader I got from the SAXParser wasn't configured to understand namespaces, which meant it didn't correctly process nillable elements such as
<myType>
<myIntegerElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</myType>
Instead of JAXB unmarshalling myIntegerElement to a null
Integer in Java it was decoding to Integer.valueOf(0)
; an important difference for my code. The solution was to set the parser factory to be namespace-aware:
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
SAXParser sp = spf.newSAXParser();
// and so on
I found this quite surprising, because if I got my XMLReader by doing XMLReaderFactory.createXMLReader()
then the reader had no problem with nillable elements, but it also didn't understand XMLConstants.FEATURE_SECURE_PROCESSING.
Well, first of all the xmlstreamfactory stuff is part of the jdk, so you don't need to "bring in implementations" of them. second, you can always parse the DOM yourself (safely) and then execute JAXB on the DOM instead of the raw stream. finally, you could also create your own SAXParser (configured for secure processing), and pass that to JAXB (which Blaise mentioned, just saw that) (the builtin jaxb impl in the jdk uses an XMLReader from a SAXParser as the internal parser for an InputStream).
javax.xml.parsers.SAXParserFactory
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
SAXParser sp = spf.newSAXParser();
XMLReader xmlReader = sp.getXMLReader();
SAXSource saxSource = new SAXSource(xmlReader, inputSource);
精彩评论