You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 21 Next »

XPath injection occurs when an XML document is used for data storage in a manner similar to a relational database. This attack is similar to SQL injection (MSC33-J. Prevent against SQL Injection), wherein an attacker can enter valid query logic into data fields. Most often, the conditional field of the query resolves to a tautology or gives the attacker access to privileged information.

This rule is a specific example of the broadly scoped rule FIO35-J. Validate user input.

XPath Injection Example

Consider the following XML schema.

<users>
  <user>
    <login>Utah</login>
    <password>C^f3</password>
  </user>
  <user>
    <login>Bohdi</login>
    <password>C@fe</password>
  </user>
  <user>
    <login>Busey</login>
    <password>cAf3</password>
  </user>
</users>

Unsecured code will attempt to retrieve a user from this file with an XPath statement constructed dynamically from user input.

str_query = "//users/user[LoginID/text()= " & login & 
            " and password/text()=" & password & "]"

Consequently, the user may specify input such as login = "' or 1=1" and password = "' or 1=1", yielding the following query string.

//users/user[LoginID/text()='' or 1=1  and password/text()='' or 1=1]

This will subsequently reveal all the records in the XML file

Noncompliant Code Example

Consider the following example in the context of the attack illustrated above. A username and password is read from the user and used to construct the query string.

class XpathInjection {
  private boolean doLogin(String loginID, String password)
    throws ParserConfigurationException, SAXException,IOException, XPathExpressionException {

    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    domFactory.setNamespaceAware(true);
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document doc = builder.parse("users.xml");

    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath = factory.newXPath();
    XPathExpression expr = xpath.compile("//users/user[login/text()='" + 
         loginID +"'" + "and password/text()='"+password+"' ]");
    Object result = expr.evaluate(doc, XPathConstants.NODESET);
    NodeList nodes = (NodeList) result;
    // print first names to the console 
    for (int i = 0; i < nodes.getLength(); i++) {
      System.out.println(nodes.item(i).getNodeValue());}       
         
    return (nodes.getLength() >= 1);
  }
}

The evaluate function call will return a set of all nodes in the XML file, causing the login function to return true, and bypassing authorization.

Compliant Solution

XPath injection can be prevented by adopting defenses similar to SQL injection. These include:

  • Treat all user input as untrusted
  • When validating user input, verify the data type, length, format and the content. For example, use a regular expression that checks for XML tags and special characters in user input
  • In a client-server application, perform validation at both the client and server side
  • Extensively test applications which supply or use user input

In similar vulnerabilities such as SQL injection, one recommended practice is to use a technique called parameterization. In this technique, user-specified data is passed directly to an API as a parameter, which in turn ensures that no data specified by the user is interpreted as executable logic. Unfortunately, such an interface does not currently exist in Java. However, this functionality can be emulated by using an interface such as XQuery, which enables the user to effectively parameterize data by specifying a query statement in a separate file, and supply the query at runtime. Consider the example illustrated above, the following query specified in a text file, and the following source code.

Input File: login.qry

declare variable $loginID as xs:string external;
declare variable $password as xs:string external;//users/user[@loginID=
$loginID and @password=$password]

Source Code

Document doc = new Builder().build("users.xml");
XQuery xquery = new XQueryFactory().createXQuery(new File("dologin.xq"));

Map queryVars= new HashMap();

queryVars.put("loginid", "Utah");
queryVars.put("password", "test123");

Nodes results = xquery.execute(doc, null, vars).toNodes();

for (int i=0; i < results.size(); i++) {
  System.out.println(results.get(i).toXML());
}

Using this method, the data specified in loginID and password fields will not be interpreted as executable expressions at runtime.

Risk Assessment

Failing to validate user input may result in information disclosure and execution of unprivileged actions.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MSC35- J

medium

probable

medium

P8

L2

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

[[Fortify 08]] "Input Validation and Representation: XML Injection"
[[Sen 07]]
[[Sun 06]] Ensure Data Security
[[OWASP 05]] Testing for XPath Injection


MSC34-J. Prevent XML Injection      49. Miscellaneous (MSC)      MSC36-J. Understand how escape characters are interpreted when String literals are compiled

  • No labels