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 , (see VOID IDS07IDS00-J. Prevent SQL Injection) wherein an Sanitize untrusted data passed across a trust boundary). An attacker can enter valid SQL or XML constructs into in the data fields of the query in use. TypicallyIn typical attacks, the conditional field of the query resolves to a tautology or otherwise gives the attacker access to privileged information.
This guideline is a specific example of the broadly scoped guideline void Filter data that passes through a trust boundary IDS52-J. Prevent 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 attempt to retrieve user details from this file with an XPath statement constructed dynamically from user input.
Code Block |
---|
//users/user[LoginIDusername/text()='&LOGIN&' and password/text()='&PASSWORD&' ] |
If an attacker knows that Utah
is a valid login ID, they user name, he or she can specify an input login ID such as:
Code Block |
---|
Utah' or '1'='1
|
This would yield yields the following query string:.
Code Block |
---|
//users/user[loginusername/text()='Utah' or '1'='1' and password/text()='xxxx' ] |
Since Because the '1'='1'
is automatically true, the password is never validated. Consequently, the attacker is falsely logged in inappropriately authenticated as user Utah
, without having to know the password.
In order to comply with guideline MSC05-J. Store passwords using a hash function, the passwords would have to be encrypted. Unfortunately, on many small systems, they are not, and so the password text added in the query string would match precisely what the user enters. An attacker could supply a password such as:
Code Block |
---|
' or '1'='1
|
This would yield the following query string:
Code Block |
---|
//users/user[password/text()='xxxx' and login/text()='' or '1'='1' ]
|
This time, the '1'='1'
tautology disables both login ID and password validation, and the attacker is falsely logged in without knowing a login ID or password without knowing Utah
's password.
Noncompliant Code Example
In this This noncompliant code example , reads a user name and password is read from the user and used uses them to construct the query string. The password is passed as a char
array , and then hashed, all to comply with MSC05-J. Store passwords using a hash function and MSC56-J. Limit the lifetime of sensitive data.If passed the attack string for login
described above, the evaluate()
. 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 login node in the XML file, causing the logindoLogin()
method to return true
and bypass any authorization.
Code Block | ||
---|---|---|
| ||
private boolean doLogin(String loginIDuserName, char[] 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()='" + loginIDuserName + "' and password/text()='" + pwd + "' ]"); 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++) { Node node = nodes.item(i).getChildNodes().item(1).getChildNodes().item(0); System.out.println( "Authenticated: " + node.getNodeValue()); } return (nodes.getLength() >= 1); } |
Compliant Solution (XQuery)
XPath injection can be prevented by adopting defenses similar to those used to prevent SQL injection:
- Treat all user input as untrusted, and perform appropriate sanitization.
- When 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 guideline void Filter data that passes through a trust boundary . 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 that supply, propagate, or use accept user input.
An effective prevention technique for preventing the related issue of SQL injection is parameterization, whereby . Parameterization ensures that user-specified data is passed to an API as a parameter , thus ensuring that user-specified such that the data is never interpreted as executable logiccontent. Unfortunately, Java SE currently lacks an analogous interface for XPath queries. However, an XPath analog to SQL parameterization can be emulated by using an interface ( such as XQuery ) that supports specifying a query statement in a separate file that is supplied at runtime.
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] |
This compliant solution uses a query specified in a text file by reading the file in the required format and then entering inserting values for the user name and password in a Map
. The XQuery
library constructs the XML query from these elementsinputs.
Code Block | ||
---|---|---|
| ||
private boolean doLogin(String loginIDuserName, String pwd) 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("login.xryxq")); Map queryVars = new HashMap(); queryVars.put("loginiduserName", loginIDuserName); queryVars.put("password", pwd); NodeList nodes = xquery.execute(doc, null, queryVars).toNodes(); // Print first names to the console for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i).getChildNodes().item(1).getChildNodes().item(0); System.out.println( node.getNodeValue()); } return (nodes.getLength() >= 1); } |
Using this method, the data specified in the loginID
and userName
and password
fields cannot be interpreted as executable content at runtime.
Wiki Markup |
---|
In addition, OWASP \[[OWASP 2005|AA. Bibliography#OWASP 05]\] recommends |
Applicability
Failure to validate user input may result in information disclosure and execution of unprivileged code.
According to OWASP [OWASP 2014],
[Prevention of XPath injection] requires the following characters to be removed (that is, prohibited) or properly
\[Prevention of XPath injection\] requires the following characters to be removed (ie prohibited) or properly escaped: Wiki Markup
< > / ' = "
to to prevent straight parameter injection.- XPath queries should not contain any meta characters (such as as
' = * ? //
or or similar).- XSLT expansions should not contain any user input, or if they do, that [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
Risk Assessment
Failure to validate user input may result in information disclosure and execution of unprivileged code.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS09-J | medium | probable | medium | P8 | L2 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
Wiki Markup |
---|
\[[Fortify 2008|AA. Bibliography#Fortify 08]\] "Input Validation and Representation: XML Injection"
\[[MITRE 2009|AA. Bibliography#MITRE 09]\] [CWE ID 643|http://cwe.mitre.org/data/definitions/247.html] "Failure to Sanitize Data within XPath Expressions (aka 'XPath injection')"
\[[OWASP 2005|AA. Bibliography#OWASP 05]\] [Testing for XPath Injection|http://www.owasp.org/index.php/XPath_Injection_Testing_AoC]
\[[Sen 2007|AA. Bibliography#Sen 07]\]
\[[Sun 2006|AA. Bibliography#Sun 06]\] [Ensure Data Security|http://java.sun.com/developer/technicalArticles/xml/jaxp1-3/index.html#Ensure%20Data%20Security] |
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 |
...