...
Code Block |
---|
<users> <user> <username>Utah</username> <password>C^f3<<password>e90205372a3b89e2</password> </user> <user> <username>Bohdi</username> <password>C@fe<<password>6c16b22029df4ec6</password> </user> <user> <username>Busey</username> <password>cAf3<<password>ad39b3c2a4dabc98</password> </user> </users> |
The passwords are hashed in compliance with MSC66-JG. Store passwords using a hash function.
Untrusted code may attempt to retrieve user details from this file with an XPath statement constructed dynamically from user input:
...
If an attacker knows that Utah
is a valid user name, he or she they can specify an input such as the following:
...
Code Block |
---|
//users/user[username/text()='Utah' or '1'='1' and password/text()='xxxx' ]
|
Because the '1'='1'
is automatically true, the password is never validated. Consequently, the attacker is inappropriately authenticated as user Utah
without knowledge of user Utah
's password.
Compliance with MSC66-JG. Store passwords using a hash function requires encrypting the passwords. Unfortunately, many small systems fail to comply with MSC51-J, 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 yields the following query string:
Code Block |
---|
//users/user[username/text()='xxxx' and password/text()='' or '1'='1' ]
|
This time, the '1'='1'
tautology disables both name and password validation, and the attacker is inappropriately authenticated without knowledge of either a user name or a password.
Noncompliant Code Example
This noncompliant code example reads a user name and password from the user and uses them to construct the query string. The password is passed as a char
array, and then hashed, to comply with MSC66-JG. Store passwords using a hash function and MSC63-JG. Limit the lifetime of sensitive data.. 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. This causes the doLogin()
method to return true
and bypass any authorization.
Code Block | ||
---|---|---|
| ||
private boolean doLogin(String userName, 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[username/text()='" + userName + "' 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); } |
...