...
A whitelist can be used to restrict input to a list of valid characters. Characters and character sequences that must be excluded from whitelists — including whitelists—including Java Naming and Directory Interface (JNDI) metacharacters and LDAP special characters — are:characters—are listed in the following table.
Characters and Sequences to Exclude from Whitelists
Character | Name |
---|---|
| Single and double quote |
| Forward slash and backslash |
| Double slashes* |
space | Space character at beginning or end of string |
| Hash character at the beginning of the string |
| Angle brackets |
| Comma and semicolon |
| Addition and multiplication operators |
| Round braces |
| Unicode |
* This is a character sequence.
LDAP Injection Example
Consider an LDAP Data Interchange Format (LDIF) file that contains records in the following format:
...
A search for a valid user name and password often takes the form:
Code Block |
---|
(&(sn=<USERSN>)(userPassword=<USERPASSWORD>)) |
However, an attacker could bypass authentication by using S*
for the USERSN
field and *
for the USERPASSWORD
field. Such input would yield every record whose USERSN
field began with S.
An authentication routine that permitted LDAP injection would allow unauthorized users to log in. Likewise, a search routine would allow an attacker to discover part or all of the data in the directory.
Noncompliant Code Example
This noncompliant code example allows a caller of the method searchRecord()
to search for a record in the directory using the LDAP protocol. The string filter
is used to filter the result set for those entries that match a user name and password supplied by the caller. When a malicious user enters specially crafted input, as outlined previously, this elementary authentication scheme fails to confine the output of the search query to the information for which the user has access privileges.
Code Block | ||
---|---|---|
| ||
// String userSN = "S*"; // Invalid // String userPassword = "*"; // Invalid public class LDAPInjection { private void searchRecord(String userSN, String userPassword) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); try { DirContext dctx = new InitialDirContext(env); SearchControls sc = new SearchControls(); String[] attributeFilter = {"cn", "mail"}; sc.setReturningAttributes(attributeFilter); sc.setSearchScope(SearchControls.SUBTREE_SCOPE); String base = "dc=example,dc=com"; // The following resolves to (&(sn=S*)(userPassword=*)) String filter = "(&(sn=" + userSN + ")(userPassword=" + userPassword + "))"; NamingEnumeration<?> results = dctx.search(base, filter, sc); while (results.hasMore()) { SearchResult sr = (SearchResult) results.next(); Attributes attrs = (Attributes) sr.getAttributes(); Attribute attr = (Attribute) attrs.get("cn"); System.out.println(attr.get()); attr = (Attribute) attrs.get("mail"); System.out.println(attr.get()); } dctx.close(); } catch (NamingException e) { // HandleForward to handler } } } |
When a malicious user enters specially crafted input, as outlined previously, this elementary authentication scheme fails to confine the output of the search query to the information for which the user has access privileges.
Compliant Solution
This compliant solution uses a whitelist to sanitize user input so that the filter
string contains only valid characters. In this code, userSN
may contain only letters and spaces, whereas a password may contain only alphanumeric characters.
Code Block | ||
---|---|---|
| ||
// String userSN = "Sherlock Holmes"; // Valid // String userPassword = "secret2"; // Valid // ... beginning of LDAPInjection.searchRecord()... sc.setSearchScope(SearchControls.SUBTREE_SCOPE); String base = "dc=example,dc=com"; if (!userSN.matches("[\\w\\s]*") || !userPassword.matches("[\\w]*")) { throw new IllegalArgumentException("Invalid input"); } String filter = "(&(sn = " + userSN + ")(userPassword=" + userPassword + "))"; // ... remainder of LDAPInjection.searchRecord()... |
When a database field such as a password must include special characters, it is critical to ensure that the authentic data is stored in sanitized form in the database and also that any user input is normalized before the validation or comparison takes place. We discourage use of Using characters that have special meanings in JNDI and LDAP in the absence of a comprehensive normalization and whitelisting-based routine . Refer to IDS50-JG. Properly encode or escape output for examples on output encoding and escapingis discouraged. Special characters must be transformed to sanitized, safe values before they are added to the whitelist expression against which input will be validated. Likewise, normalization of user input (escaping and encoding) should occur before the validation step.
...
Applicability
Failure to sanitize untrusted input can result in information disclosure and privilege escalation.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS53-JG | high | likely | medium | P18 | L1 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
...
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
The Checker Framework |
| Tainting Checker | Trust and security errors (see Chapter 8) | ||||||
Parasoft Jtest |
| CERT.IDS54.TDLDAP | Protect against LDAP injection | ||||||
SonarQube |
| S2078 |
Bibliography
...