XPath injection occurs when an XML document is Extensible Markup Language (XML) can be used for data storage in a manner similar to a relational database. Data is frequently retrieved from such an XML document using XPaths. XPath injection can occur when data supplied to an XPath retrieval routine to retrieve data from an XML document is used without proper sanitization. This attack is similar to SQL injection or XML injection (MSC33see IDS00-J. Prevent against SQL Injection), wherein an attacker is able to enter valid query logic into data fields. Most oftenSanitize untrusted data passed across a trust boundary). An attacker can enter valid SQL or XML constructs in the data fields of the query in use. In typical attacks, the conditional field of the query resolves to a tautology or otherwise gives the attacker access to privileged information.
This rule guideline is a specific example of the broadly scoped rule FIO35IDS52-J. Validate user inputPrevent code injection.
...
XML Path Injection Example
Consider the following XML schema.:
Code Block |
---|
<users> <user> <login>Utah<<username>Utah</login>username> <password>C^f3<<password>e90205372a3b89e2</password> </user> <user> <login>Bohdi<<username>Bohdi</login>username> <password>C@fe<<password>6c16b22029df4ec6</password> </user> <user> <login>Busey<<username>Busey</login>username> <password>cAf3<<password>ad39b3c2a4dabc98</password> </user> </users> |
The passwords are hashed in compliance with MSC62-J. Store passwords using a hash function. MD5 hashes are shown here for illustrative purposes; in practice, you should use a safer algorithm such as SHA-256.
Untrusted code may Unsecured code will attempt to retrieve a user details from this file with an XPath statement constructed dynamically from user input.
Code Block |
---|
str_query = "//users/user[LoginIDusername/text()= " & login & " '&LOGIN&' and password/text()=" & password & "]" '&PASSWORD&' ] |
If an attacker knows that Utah
is a valid user name, he or she can specify an input such as
Code Block |
---|
Utah' or '1'='1
|
This yields Therefore, the user may specify input such as login = "' or 1=1
" and password = "' or 1=1
", yielding the following query string.
Code Block |
---|
//users/user[LoginIDusername/text()='Utah' or '1'='1' and password/text()='' or 1=1] xxxx'] |
Because the '1'='1'
is automatically true, the password is never validated. Consequently, the attacker is inappropriately authenticated as user Utah
without knowing Utah
's password.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 This noncompliant code example reads a user name and password from the user and used uses them to construct the query string. The password is passed as a char
array and then hashed. This example is vulnerable to the attack described earlier. If the attack string described earlier is passed to evaluate()
, the method call returns the corresponding node in the XML file, causing the doLogin()
method to return true
and bypass any authorization.
Code Block | ||
---|---|---|
| ||
class XpathInjection { private boolean doLogin(String loginIDuserName, Stringchar[] password) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder builder = domFactory.newDocumentBuilder(); Document doc = builder.parse("users.xml"); String pwd = hashPassword( password); XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//users/user[loginusername/text()='" + userName loginID+ +"'" + "and password/text()='" +password pwd + "' ]"); Object result = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodes = (NodeList) result; // printPrint first names to the console for (int i = 0; i < nodes.getLength(); i++) { Node node System.out.println(nodes= nodes.item(i).getChildNodes().item(i1).getNodeValuegetChildNodes().item(0);} System.out.println( "Authenticated: " + node.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 (XQuery)
XPath injection can be prevented by adopting defenses similar to those used to prevent SQL injection. These include:
- Treat all user input as untrusted, and perform appropriate sanitization.
- When validating sanitizing user input, verify the correctness of 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. This practice corresponds to input sanitization. See IDS52-J. Prevent code injection for additional details.
- In a client-server application, perform validation at both the client and the server sidesides.
- Extensively test applications which that supply, propagate, or use accept user input.
An effective technique for preventing the related issue of SQL injection is parameterization. Parameterization ensures that 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 such that the data is never interpreted as executable logiccontent. Unfortunately, such Java SE currently lacks an interface does not currently exist in Javaanalogous interface for XPath queries. However, this functionality an XPath analog to SQL parameterization can be emulated by using an interface such as XQuery , which enables the user to effectively parameterize data by that supports specifying a query statement in a separate file , and supply the query supplied at runtime. Consider the example illustrated above, the following query specified in a text file, and the following source code.
Input File: login.qry
Code Block |
---|
declare variable $loginID$userName as xs:string external; declare variable $password as xs:string external; //users/user[@loginID@userName= $loginID$userName and @password=$password] |
Source Code
This compliant solution uses a query specified in a text file by reading the file in the required format and then inserting values for the user name and password in a Map
. The XQuery
library constructs the XML query from these inputs.
Code Block | ||
---|---|---|
| ||
private boolean doLogin(String userName, String pwd) Document doc = new Builder().build throws ParserConfigurationException, SAXException, IOException, XPathExpressionException { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder builder = domFactory.newDocumentBuilder(); Document doc = builder.parse("users.xml"); XQuery xquery = new XQueryFactory().createXQuery(new File("dologinlogin.xq")); Map queryVars = new HashMap(); queryVars.put("loginiduserName", "Utah"userName); queryVars.put("password", "test123"pwd); Nodes results NodeList nodes = xquery.execute(doc, null, varsqueryVars).toNodes(); // Print first names to the console for (int i = 0; i < resultsnodes.sizegetLength(); i++) { Node node = nodes.item(i).getChildNodes().item(1).getChildNodes().item(0); System.out.println(resultsnode.getgetNodeValue(i).toXML())); } return (nodes.getLength() >= 1); } |
Using this method, the data specified in loginID
and the userName
and password
fields will not cannot be interpreted as executable expressions content at runtime.
...
Applicability
Failing Failure 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
code.
According to OWASP [OWASP 2014],
[Prevention of XPath injection] requires the following characters to be removed (that is, prohibited) or properly escaped:
< > / ' = "
to prevent straight parameter injection.- XPath queries should not contain any meta characters (such as
' = * ? //
or similar).- XSLT expansions should not contain any user input, or if they do, [you should] comprehensively test the existence of the file, and ensure that the files are within the bounds set by the Java 2 Security Policy.
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
The Checker Framework |
| Tainting Checker | Trust and security errors (see Chapter 8) | ||||||
Parasoft Jtest |
| CERT.IDS53.TDJXPATH CERT.IDS53.TDXPATH | Protect against JXPath injection Protect against XPath injection |
Bibliography
[Fortify 2008] | "Input Validation and Representation: XML Injection" |
[Oracle 2011b] | Ensure Data Security |
[OWASP 2014] | Testing for XPath Injection |
[Sen 2007] | Avoid the Dangers of XPath Injection |
[Sun 2006] | Ensure Data Security |
...
\[[Fortify 08|AA. Java References#Fortify 08]\] "Input Validation and Representation: XML Injection"
\[[Sen 07|AA. Java References#Sen 07]\]
\[[Sun 06|AA. Java References#Sun 06]\] [Ensure Data Security|http://java.sun.com/developer/technicalArticles/xml/jaxp1-3/index.html#Ensure%20Data%20Security]
\[[OWASP 05|AA. Java References#OWASP 05]\] [Testing for XPath Injection|http://www.owasp.org/index.php/XPath_Injection_Testing_AoC] Wiki Markup