LDAP Injection
LDAP Injection
Description
LDAP Injection involves exploiting web-based applications that generate LDAP statements using user input. In cases where an application fails to properly sanitize user input, attackers can manipulate LDAP statements by injecting special keywords into the query, an attack that is similar to SQL Injection.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class LDAPSearchExample {
public static void main(String[] args) {
// Input from the user (replace this with your own input mechanism)
String userInput = "username"; // User-supplied input
// LDAP connection parameters
String ldapURL = "ldap://your-ldap-server:389";
String baseDN = "ou=users,dc=example,dc=com"; // Replace with your base DN
// Set up the environment for creating the initial context
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapURL);
try {
// Create the initial context
LdapContext ctx = new InitialLdapContext(env, null);
// Specify the search filter
String searchFilter = "(uid=" + userInput + ")";
// Set the search controls
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Perform the search
NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, searchControls);
// Iterate through the search results
while (results.hasMore()) {
SearchResult result = results.next();
// Process the result as needed (e.g., print attributes)
Attributes attributes = result.getAttributes();
System.out.println("User found: " + attributes.get("cn").get());
}
// Close the context
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
const ldap = require('ldapjs');
const userInput = 'user123';
const ldapQuery = `(uid=${userInput})`; // Vulnerable to LDAP Injection
const client = ldap.createClient({
url: 'ldap://example.com:389'
});
client.search('ou=users,dc=example,dc=com', {
filter: ldapQuery,
}, (err, res) => {
// Process search results
res.on('searchEntry', (entry) => {
// Handle entry
});
res.on('error', (err) => {
console.error('Error:', err.message);
});
});
<?php
// Vulnerable PHP code with LDAP Injection
$userInput = 'user123';
$ldapQuery = "(uid=$userInput)"; // Vulnerable to LDAP Injection
$ldapconn = ldap_connect("ldap://example.com");
ldap_bind($ldapconn, "cn=admin,dc=example,dc=com", "adminpassword");
$result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
$entries = ldap_get_entries($ldapconn, $result);
// Process search results
foreach ($entries as $entry) {
// Handle entry
}
ldap_close($ldapconn);
?>
Recommendation
To mitigate the risk of LDAP injection, consider the following recommendations:
-
Parameterized Queries: Use parameterized queries instead of direct concatenation to construct LDAP queries.
-
Input Validation / Sanitization: Implement input validation to ensure that user input adheres to expected formats and does not contain special characters that might alter LDAP queries, also sanitize user input using methods such as
LdapFilterEncode
-
Use Frameworks that Automatically Protect from LDAP Injection: Utilize well-established and secure LDAP query APIs or libraries that automatically encode user input when building LDAP queries.
-
Enabling Bind Authentication: Using bind authentication will limit the attack surface of the LDAP server if an attacker manages to perform LDAP injection.
-
Least Privilege: Least Privilege principle is a rule of the thumb advice to minimize the impact of compromised services.
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
public class LDAPSearchMitigatedExample {
public static void main(String[] args) {
// Input from the user (replace this with your own input mechanism)
String userInput = "username"; // User-supplied input
// LDAP connection parameters
String ldapURL = "ldap://your-ldap-server:389";
String baseDN = "ou=users,dc=example,dc=com"; // Replace with your base DN
// Set up the environment for creating the initial context
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapURL);
try {
// Create the initial context
LdapContext ctx = new InitialLdapContext(env, null);
// Use parameterized query to avoid LDAP injection
String searchFilter = "(uid={0})";
Object[] filterArgs = {userInput};
// Set the search controls
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Perform the search
NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, filterArgs, searchControls);
// Iterate through the search results
while (results.hasMore()) {
SearchResult result = results.next();
// Process the result as needed (e.g., print attributes)
Attributes attributes = result.getAttributes();
System.out.println("User found: " + attributes.get("cn").get());
}
// Close the context
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Mitigated JavaScript code with input validation and parameterized query
const ldap = require('ldapjs');
const userInput = 'user123';
// Perform input validation to ensure userInput is safe for LDAP query
if (isValidUserInput(userInput)) {
const ldapQuery = `(uid=${userInput})`;
const client = ldap.createClient({
url: 'ldap://example.com:389'
});
client.search('ou=users,dc=example,dc=com', {
filter: ldapQuery,
}, (err, res) => {
// Process search results
res.on('searchEntry', (entry) => {
// Handle entry
});
res.on('error', (err) => {
console.error('Error:', err.message);
});
});
} else {
console.log('Invalid userInput');
}
function isValidUserInput(userInput) {
// Implement proper input validation logic
// For example, check for allowed characters, length, etc.
return /^[a-zA-Z0-9]+$/.test(userInput);
}
<?php
// Mitigated PHP code with input validation and parameterized query
$userInput = 'user123';
// Perform input validation to ensure userInput is safe for LDAP query
if (isValidUserInput($userInput)) {
$ldapQuery = "(uid=$userInput)";
$ldapconn = ldap_connect("ldap://example.com");
ldap_bind($ldapconn, "cn=admin,dc=example,dc=com");
$result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
$entries = ldap_get_entries($ldapconn, $result);
// Process search results
foreach ($entries as $entry) {
// Handle entry
}
ldap_close($ldapconn);
} else {
echo 'Invalid userInput';
}
function isValidUserInput($userInput) {
// Implement proper input validation logic
// For example, check for allowed characters, length, etc.
return preg_match('/^[a-zA-Z0-9]+$/', $userInput);
}
?>
Links
Standards
- GDPR:
- ART_25
- ART_32
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_6_4
- REQ_6_5
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5