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]. Example in this XML document, an external entity read the /etc/passwd file: ---- ]> &xxe; Jani Reminder Don't forget me this weekend! ---- In this XSL document, network access is allowed which can lead to SSRF vulnerabilities: ---- &content; ---- It is recommended to disable access to external entities and network access in general. 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: * 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); 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. 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). 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. == Noncompliant Code Examples https://docs.oracle.com/javase/9/docs/api/javax/xml/parsers/DocumentBuilderFactory.html[DocumentBuilderFactory] library: ---- String xml = "xxe.xml"; DocumentBuilderFactory df = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = df.newDocumentBuilder(); // Noncompliant 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