V5321. OWASP. Possible LDAP injection. Potentially tainted data is used in a search filter.
The analyzer has detected that potentially tainted data is used to construct an LDAP query filter. If data is not properly sanitized, this can lead to LDAP injection, a vulnerability similar to SQL injection.
This vulnerability can be categorized under the OWASP Top 10 2021 classification as follows:
The example:
public void search(HttpServletRequest request) throws NamingException {
String user = request.getParameter("user");
String password = request.getParameter("password");
String searchFilter = "(&(uid=" + user + ")(userPassword=" + password + "))";
DirContext context = new InitialDirContext(getEnv());
var result = context.search("ou=users,dc=example,dc=com",
searchFilter, null); // <=
if (result.hasMore()) {
....
}
}
In the example, a search filter is constructed to provide some sensitive information to a user with a certain username and password. The filter uses the values of the user
and password
variables obtained from an external source. Using data in this manner is dangerous, as attackers can manipulate the search filter.
Here are a few examples to illustrate the attack.
If user
contains PVS
and password
contains Studio
, developers will get the following query:
LDAP query: (&(uid=PVS)(userPassword=Studio))
In this case, developers receive the expected data from the user. If a username and password combination are valid, access will be granted.
Consider that the following values being written in the 'user' and 'password' variables:
user: PVS)(uid=PVS))(|(uid=PVS)
password: Any
When these values are inserted into the LDAP query template, the resulting filter is:
LDAP query: (&(uid=PVS)(uid=PVS))(|(uid=PVS)(userPassword=Any))
Using such a search filter can grant access, even if attackers enter an incorrect password. This happens because LDAP will only process the first filter, and (|(uid=PVS)(userPassword=Any))
will be ignored.
To harden security, it is important to validate all input data or escape all special characters in the user-supplied data.
Here is the code example that uses the escape method to handle user-supplied data:
private static String escapeLdapInput(String input) {
return input.replace("(", "\\28").replace(")", "\\29")
.replace("*", "\\2a").replace("|", "\\7c")
.replace("&", "\\26").replace("!", "\\21")
.replace("=", "\\3d").replace(">", "\\3e")
.replace("<", "\\3c").replace("\\", "\\5c");
}
public void safeSearch(HttpServletRequest request) throws NamingException {
String user = request.getParameter("user");
String password = request.getParameter("password");
String escapedUser = escapeLdapInput(user);
String escapedPassword = escapeLdapInput(password);
String searchFilter = "(&(uid=" + escapedUser +
")(userPassword=" + escapedPassword + "))";
DirContext context = new InitialDirContext(getEnv());
var result = context.search("ou=users,dc=example,dc=com",
searchFilter, null);
if (result.hasMore()) {
....
}
}
This diagnostic is classified as:
|