GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • CodeQL documentation
  • CodeQL overview
  • Writing CodeQL queries
  • CodeQL language guides
  • QL language reference
  • CodeQL standard-libraries
  • CodeQL query help
  • CodeQL repository
  • QL publications
  • CodeQL query help for C and C++
  • CodeQL query help for C#
  • CodeQL query help for GitHub Actions
  • CodeQL query help for Go
  • CodeQL query help for Java and Kotlin

This view

  • Original page
  • New address

GeezerVison is showing codeql.github.com — XPath injection — CodeQL query help documentation

XPath injection¶

ID: java/xml/xpath-injection
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-643
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

If an XPath expression is built using string concatenation, and the components of the concatenation include user input, it makes it very easy for a user to create a malicious XPath expression.

Recommendation¶

If user input must be included in an XPath expression, either sanitize the data or pre-compile the query and use variable references to include the user input.

XPath injection can also be prevented by using XQuery.

Example¶

In the first three examples, the code accepts a name and password specified by the user, and uses this unvalidated and unsanitized value in an XPath expression. This is vulnerable to the user providing special characters or string sequences that change the meaning of the XPath expression to search for different values.

In the fourth example, the code uses setXPathVariableResolver which prevents XPath injection.

The final two examples are for dom4j. They show an example of XPath injection and one method of preventing it.

final String xmlStr = "<users>" + 
                        "   <user name=\"aaa\" pass=\"pass1\"></user>" + 
                        "   <user name=\"bbb\" pass=\"pass2\"></user>" + 
                        "</users>";
try {
    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    domFactory.setNamespaceAware(true);
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    //Document doc = builder.parse("user.xml");
    Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));

    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath = factory.newXPath();

    // Injectable data
    String user = request.getParameter("user");
    String pass = request.getParameter("pass");
    if (user != null && pass != null) {
        boolean isExist = false;

        // Bad expression
        String expression1 = "/users/user[@name='" + user + "' and @pass='" + pass + "']";
        isExist = (boolean)xpath.evaluate(expression1, doc, XPathConstants.BOOLEAN);
        System.out.println(isExist);

        // Bad expression
        XPathExpression expression2 = xpath.compile("/users/user[@name='" + user + "' and @pass='" + pass + "']");
        isExist = (boolean)expression2.evaluate(doc, XPathConstants.BOOLEAN);
        System.out.println(isExist);

        // Bad expression
        StringBuffer sb = new StringBuffer("/users/user[@name=");
        sb.append(user);
        sb.append("' and @pass='");
        sb.append(pass);
        sb.append("']");
        String query = sb.toString();
        XPathExpression expression3 = xpath.compile(query);
        isExist = (boolean)expression3.evaluate(doc, XPathConstants.BOOLEAN);
        System.out.println(isExist);

        // Good expression
        String expression4 = "/users/user[@name=$user and @pass=$pass]";
        xpath.setXPathVariableResolver(v -> {
        switch (v.getLocalPart()) {
            case "user":
                return user;
            case "pass":
                return pass;
            default:
                throw new IllegalArgumentException();
            }
        });
        isExist = (boolean)xpath.evaluate(expression4, doc, XPathConstants.BOOLEAN);
        System.out.println(isExist);


        // Bad Dom4j 
        org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
        org.dom4j.Document document = reader.read(new InputSource(new StringReader(xmlStr)));
        isExist = document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']") != null;
        // or document.selectNodes
        System.out.println(isExist);

        // Good Dom4j
        org.jaxen.SimpleVariableContext svc = new org.jaxen.SimpleVariableContext();
        svc.setVariableValue("user", user);
        svc.setVariableValue("pass", pass);
        String xpathString = "/users/user[@name=$user and @pass=$pass]";
        org.dom4j.XPath safeXPath = document.createXPath(xpathString);
        safeXPath.setVariableContext(svc);
        isExist = safeXPath.selectSingleNode(document) != null;
        System.out.println(isExist);
    }
} catch (ParserConfigurationException e) {

} catch (SAXException e) {

} catch (XPathExpressionException e) {

} catch (org.dom4j.DocumentException e) {

}

References¶

  • OWASP: Testing for XPath Injection.

  • OWASP: XPath Injection.

  • Common Weakness Enumeration: CWE-643.

  • © GitHub, Inc.
  • Terms
  • Privacy
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.