LDAP Injection
ID |
php.ldap_injection |
Severity |
critical |
Resource |
Injection |
Language |
Php |
Tags |
CWE:90, NIST.SP.800-53, OWASP:2021:A3, PCI-DSS:6.5.1 |
Description
LDAP Injection occurs when user-controlled input is improperly incorporated into LDAP queries, allowing attackers to modify the query logic and potentially access or manipulate unauthorized data.
Rationale
LDAP Injection is a security vulnerability that arises when an application dynamically constructs LDAP queries using unsanitized user input. If an attacker injects special LDAP characters, they can alter the intended query logic, bypass authentication mechanisms, or extract sensitive data from the directory service.
Consider the following vulnerable PHP code, which attempts to authenticate a user via LDAP:
<?php
$ldapconn = ldap_connect("ldap://example.com");
if (!$ldapconn) {
die("Could not connect to LDAP server.");
}
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$username = $_POST['username'];
$password = $_POST['password'];
// Vulnerable query construction
$filter = "(&(uid=$username)(userPassword=$password))";
$search = ldap_search($ldapconn, "dc=example,dc=com", $filter);
$result = ldap_get_entries($ldapconn, $search);
if ($result["count"] > 0) {
echo "Authentication successful.";
} else {
echo "Invalid username or password.";
}
An attacker can exploit this by entering )(uid=) as the username, effectively modifying the query to retrieve all users, potentially bypassing authentication.
This effectively broadens the search filter beyond the intended scope, potentially exposing all entries in the directory.
Remediation
To mitigate LDAP Injection in PHP, the following best practices should be applied:
-
Escape User Input: Use ldap_escape() to properly sanitize user input before inserting it into LDAP queries.
-
Use Parameterized Queries: If supported by the LDAP library, prefer prepared queries.
-
Limit Query Scope: Avoid exposing unnecessary attributes and restrict LDAP searches to specific organizational units.
-
Authenticate Securely: Instead of searching for a user via ldap_search(), use ldap_bind() for authentication.
Here is the secure version of the previous example:
<?php
$ldapconn = ldap_connect("ldap://example.com");
$ldapconn = ldap_connect("ldap://example.com");
if (!$ldapconn) {
die("Could not connect to LDAP server.");
}
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$username = ldap_escape($_POST['username'], "", LDAP_ESCAPE_FILTER);
$password = $_POST['password'];
// Secure authentication using ldap_bind
$bind_dn = "uid=$username,ou=users,dc=example,dc=com";
$bind = @ldap_bind($ldapconn, $bind_dn, $password);
if ($bind) {
echo "Authentication successful.";
} else {
echo "Invalid username or password.";
}
By using ldap_escape(), we ensure that special characters are properly escaped, preventing attackers from altering LDAP queries. Additionally, ldap_bind() is used instead of ldap_search() for authentication, reducing the attack surface significantly.