logo

Database

Need

Separation of user input from XPath expressions through variables

Context

• Usage of Kotlin 1.9+ on the JVM for building web applications

• Usage of the javax.servlet API for handling HTTP requests

• Usage of the javax.xml.xpath API for querying XML documents

Description

1. Non compliant code

import javax.servlet.http.HttpServletRequest
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory
import org.w3c.dom.Document
import org.w3c.dom.Node

fun findUser(request: HttpServletRequest, users: Document): Node? {
    val name = request.getParameter("name").orEmpty()...

The `findUser` function below builds an XPath expression by inserting the `name` request parameter between single quotes with a string template, and evaluates it against the users document. XPath has its own syntax, and the parameter is inserted without escaping. A value such as `' or '1'='1` turns the condition into one that is always true, so the query returns the first user of the document regardless of the name. When the query is part of a login check, this bypasses authentication; with functions such as `substring` and `string-length`, an attacker can also extract any value of the document, one character at a time.

2. Steps

• Never build XPath expressions with string templates or concatenation from request data.

• Write constant expressions that reference variables such as `$name`, and bind values with `XPath.setXPathVariableResolver`.

• Validate identifiers against a strict pattern when they cannot be passed as variables.

• Avoid storing credentials or other secrets in XML documents that are queried with user input.

3. Secure code example

import javax.servlet.http.HttpServletRequest
import javax.xml.namespace.QName
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactory
import org.w3c.dom.Document
import org.w3c.dom.Node

fun findUser(request: HttpServletRequest, users: Document): Node? {...

The corrected function writes the XPath expression as a constant that refers to the variable `$name`, and supplies the value through an `XPathVariableResolver`. The XPath engine treats a variable as a value, never as part of the expression, so quotes, brackets or `or` clauses inside the parameter cannot change the structure of the query. This is the XPath equivalent of a parameterized SQL query. The expression is also compiled once with `compile`, which avoids parsing it on every request.

References

• 021. XPath injection