...
Code Block |
---|
//users/user[LoginID/text()='&LOGIN&' and password/text()='&PASSWORD&' ] |
An attacker may specify input If an attacker knows that Utah
is a valid login ID, they can specify an input login ID such as:
Code Block |
---|
Utah' or 1''=1' |
for both the login and password fields. This would yield the following query string:
Code Block |
---|
//users/user[LoginIDlogin/text()='Utah' or 1''=1'' and password/text()='' or 1=1xxxx' ] |
This may expose all the records in the XML fileThe ''=''
is automatically true, and causes the password to never be validated. Consequently the attacker is falsely logged in as user Utah
.
Noncompliant Code Example
...
If passed the attack string for login
described above, the evaluate()
method call returns a set of all nodes in the XML file, causing the login()
method to return true
and bypass any authorization.
Code Block | ||
---|---|---|
| ||
class XpathInjection { private boolean doLogin(String loginID, 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[login/text()='" + loginID + "' 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 = System.out.println(nodesnodes.item(i).getChildNodes().item(i1).getNodeValuegetChildNodes().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:
...
This compliant solution uses a query specified in a text file by reading the file in the required format and then entering values for the user name and password in a Map
. The XQuery
library constructs the XML query from these elements.
Code Block | ||
---|---|---|
| ||
Document doc = new Builder().build private boolean doLogin(String loginID, 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.xry")); Map queryVars = new HashMap(); queryVars.put("loginid", loginID); // eg "Utah" queryVars.put("password", pwd); // eg "C^f3" Nodes results NodeList nodes = xquery.execute(doc, null, queryVars).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(results node.getgetNodeValue(i).toXML())); } return (nodes.getLength() >= 1); } |
Using this method, the data specified in the loginID
and password
fields cannot be interpreted as executable content at runtime.
...