The Lightweight Directory Access Protocol (LDAP) allows an application to remotely perform operations such as searching and modifying records existing in directories. LDAP injection results from inadequate input sanitization and validation and allows malicious users to glean restricted information using the directory service.
A white-list whitelist can be used to restrict input to a list of valid characters. The list of characters Characters and character sequences that must not be allowed in a white-list include JNDI meta-characters and LDAP special characters. They are tabulated below:be excluded from whitelists—including Java Naming and Directory Interface (JNDI) metacharacters and LDAP special 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
For the purpose of this example, consider Consider an LDAP Data Interchange Format (LDIF) file that contains records in the following format:
Code Block |
---|
dn: dc=example,dc=com objectclass: dcobject objectClass: organization o: Some Name dc: example dn: ou=People,dc=example,dc=com ou: People objectClass: dcobject objectClass: organizationalUnit dc: example dn: cn=Manager,ou=People,dc=example,dc=com cn: Manager sn: John Watson # Several objectClass definitions here (omitted) userPassword: secret1 mail: john@holmesassociates.com dn: cn=Senior Manager,ou=People,dc=example,dc=com cn: Senior Manager sn: Sherlock Holmes # Several objectClass definitions here (omitted) userPassword: secret2 mail: sherlock@holmesassociates.com |
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 responsible for filtering used to filter the result set on the basis of for those entries that match a user name and password that the caller must supply. If a malicious user enters specially crafted input, this elementary authentication scheme fails to confine the output of the search query to the information that the user is privileged to access. For example, the user may see any record beginning with "S" by supplying the values S*
and *
for the string variables userSN
and UserPassword
respectively. Consequently, information about any user can be gleaned without any prior knowledge of a particular user name and password pairsupplied by the caller.
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) { // Forward to Handlehandler } } } |
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 white-list whitelist to validate sanitize user input so that the filter
string contains only valid characters appear in the filter
string. For example. 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("[a-zA-Z\\w\\s]*") || !userPassword.matches("[a-zA-Z0-9\\w]*")) { throw new IllegalArgumentException("Invalid input"); } String filter = "(&(sn = " + userSN + ")(userPassword=" + userPassword + "))"; // ... remainder of LDAPInjection.searchRecord()... |
If it is desired to include special characters in When a database field such as a password must include special characters, it is critical to ensure that the authentic data is stored in a sanitized form in the database and also that any user input is escaped and transformed into the equivalent form, normalized before the validation or comparison takes place. The use of Using characters that have special meanings in JNDI and LDAP is strongly discouraged unless in the absence of a comprehensive whitenormalization and whitelisting-listing based routine is employed to encode and escape the characters. Refer to the guideline IDS04-J. Properly encode or escape output for examples on output encoding and escaping. The special character discouraged. Special characters must be transformed to a sanitized, safe value before adding it values before they are added to the white-list whitelist expression against which input is required to will be validated. Likewise, sanitization normalization of user input (escaping and encoding) should occur before the validation step.
...
Applicability
Failing Failure to sanitize untrusted input can result in information disclosure and privilege escalation.
...
Automated Detection
Tool |
---|
Version |
---|
Checker |
---|
Description |
---|
Level
IDS11- J
high
likely
medium
P18
L1
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\]
\[[OWASP 08|AA. Java References#OWASP 08]\] [Preventing LDAP Injection in Java|http://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java] |
The Checker Framework |
| Tainting Checker | Trust and security errors (see Chapter 8) | ||||||
Parasoft Jtest |
| CERT.IDS54.TDLDAP | Protect against LDAP injection | ||||||
SonarQube |
| S2078 |
Bibliography
...
IDS10-J. Prevent XML external entity attacks 10. Input Validation and Data Sanitization (IDS) IDS12-J. Prevent code injection