XML injection (XXE)
Need
Parsing of untrusted XML with document type declarations and external entities disabled
Context
• Usage of Kotlin 1.9+ on the JVM for building application services
• Usage of the JAXP SAX parser for processing XML documents
Description
1. Non compliant code
import java.io.StringReader
import javax.xml.parsers.SAXParserFactory
import org.xml.sax.InputSource
import org.xml.sax.helpers.DefaultHandler
fun parseOrder(xml: String, handler: DefaultHandler) {
// The default factory resolves external entities such as file:///etc/passwd
val parser = SAXParserFactory.newInstance().newSAXParser()...The `parseOrder` function below parses XML received from clients with a `SAXParser` created from the default `SAXParserFactory`. By default, JAXP parsers process document type declarations and resolve external entities. A document that declares `<!ENTITY xxe SYSTEM "file:///etc/passwd">` and uses `&xxe;` in a field makes the parser read that file and insert it into the parsed data, which the application may then return or store. With `http://` entities, the attacker can make the server send requests to internal hosts, and nested entity definitions ("billion laughs") can exhaust its memory.
2. Steps
• Enable `http://apache.org/xml/features/disallow-doctype-decl` on every `SAXParserFactory`, `DocumentBuilderFactory` and `XMLInputFactory` that parses untrusted data.
• Disable external general and parameter entities and XInclude processing.
• Enable `XMLConstants.FEATURE_SECURE_PROCESSING` to limit entity expansion.
• Configure the factory once and reuse it, so no code path creates an unprotected parser.
• Prefer JSON for data exchanged with clients when XML features are not needed.
3. Secure code example
import java.io.StringReader
import javax.xml.XMLConstants
import javax.xml.parsers.SAXParserFactory
import org.xml.sax.InputSource
import org.xml.sax.helpers.DefaultHandler
private val factory: SAXParserFactory = SAXParserFactory.newInstance().apply {
// Reject DOCTYPE declarations and never resolve external entities...The corrected function configures the factory before creating the parser. The `disallow-doctype-decl` feature makes the parser reject any document that contains a `DOCTYPE`, which removes both external entities and entity expansion attacks at once. The external general and parameter entity features are also turned off as a second layer, `isXIncludeAware` stays `false`, and `FEATURE_SECURE_PROCESSING` enables the JDK limits on entity expansion and document size. Documents that legitimately need a DTD are rare in APIs. When one is required, keep `disallow-doctype-decl` off but keep the external entity features disabled, and never resolve entities from untrusted documents.
References
• 083. XML injection (XXE)