Recently, we had a security audit on our code, and one of the problem is that our application is subject to the Xml eXternal Entity (XXE) attack.
Basically, the application is a calculator that receives inputs as XML, through a Web-Service.
Here is an example of such an XXE attack on our application:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header/> <soapenv:Body> <foo:calculateStuff> <!--Optional:--> <xmlInput><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE currency [ <!ENTITY include SYSTEM "file:///d:/" >]> <calcinput>...</calcinput> ]]></xmlInput> </foo:calculateStuff> </soapenv:Body> </soapenv:Envelope>
As you can see, we can refer to an entity that points to an external file ("file:///d:/"
).
Regarding the XML input itself (the <calcinput>...</calcinput>
part) is unmarshalled with JAXB (v2.1). The web-service part is based on jaxws-rt (2.1).
What do I need to do to secure my web-service?
The safest way to prevent XXE is always to disable DTDs (External Entities) completely. Depending on the parser, the method should be similar to the following: factory. setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
In most cases, XXE attacks can easily be prevented by disabling features making the XML processor weak and the application vulnerable. By analyzing the XML parsing library of the application, features that can be misused can be identified and disabled. DTD and XML external entity features must be disabled.
Generally JAXB is quite efficient and you shouldn't care about memory issues unless your application handles XMLs of very large size.
JAXB
You can prevent the Xml eXternal Entity (XXE) attack by unmarshalling from an XMLStreamReader
that has the IS_SUPPORTING_EXTERNAL_ENTITIES
and/or XMLInputFactory.SUPPORT_DTD
properties set to false
.
JAX-WS
A JAX-WS implementation should take care of this for you. If it doesn't I would recommend opening a bug against the specific implmententation.
EXAMPLE
Demo
package xxe; import javax.xml.bind.*; import javax.xml.stream.*; import javax.xml.transform.stream.StreamSource; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); XMLInputFactory xif = XMLInputFactory.newFactory(); xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/xxe/input.xml")); Unmarshaller unmarshaller = jc.createUnmarshaller(); Customer customer = (Customer) unmarshaller.unmarshal(xsr); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(customer, System.out); } }
input.xml
This XML document contains an entity that has been setup to get the listing of files I used to create this example.
<?xml version="1.0"?> <!DOCTYPE customer [ <!ENTITY name SYSTEM "/Users/bdoughan/Examples/src/xxe/"> ] > <customer> <name>&name;</name> </customer>
Customer
package xxe; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Output - Default Configuration
By default the entity will be resolved.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <customer> <name>Customer.java Demo.java input.xml </name> </customer>
Output when XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES
property is set to false
When this property is set the entity is not resolved.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <customer> <name></name> </customer>
Output when XMLInputFactory.SUPPORT_DTD
property is set to false
When this property is set an exception is thrown trying to resolve the entity.
Exception in thread "main" javax.xml.bind.UnmarshalException - with linked exception: [javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15] Message: The entity "name" was referenced, but not declared.] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:436) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:372) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:342) at xxe.Demo.main(Demo.java:18) Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15] Message: The entity "name" was referenced, but not declared. at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598) at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:196) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:370) ... 2 more
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With