Skip to main content

LDAP injection

Need

Prevention of LDAP injection attacks

Context

  • Usage of PHP 5.6+ for developing web applications
  • Usage of LDAP for Lightweight Directory Access Protocol integration

Description

Non compliant code

<?php
$username = $_POST['username'];
$password = $_POST['password'];

$query = "(&(uid=" . $username . ")(userPassword=" . $password . "))";

$ds=ldap_connect("localhost");
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ds);

$sr=ldap_search($ds, "o=My Company, c=US", $query);
$info = ldap_get_entries($ds, $sr);
?>

In the above code, the application is using user-supplied input to construct an LDAP query. The $username and $password variables are directly taken from the POST request without any sanitization or validation. This could lead to an LDAP Injection attack if the user provides a malicious input.

For instance, if a user provides the username as admin)(uid=*))(|(uid=*, the query becomes (&(uid=admin)(uid=*))(|(uid=*)(userPassword=)), which will return all the users as it translates to "users where uid is admin and uid is anything OR uid is anything", bypassing the password check.

This vulnerability allows an attacker to manipulate the query to retrieve sensitive information, modify content, or even execute certain operations with LDAP, depending on the permissions set on the LDAP server. The potential impact could be data loss, unauthorized access, or even a complete system compromise in certain scenarios.

To fix this vulnerability, user input should always be validated, sanitized, or parameterized before using in LDAP queries. The Laravel framework provides numerous ways to validate and sanitize user inputs.

Steps

  • Validate and sanitize the user input. Use a whitelist of acceptable inputs.
  • Use parameterized LDAP queries or prepared statements, if available.
  • Use LDAP escaping functions to ensure that special characters in the input do not alter the query structure.
  • Limit the permissions of the LDAP account used by the application to minimize potential damage.
  • Implement error handling that does not reveal information about the LDAP structure or query.

Compliant code

<?php
$username = $_POST['username'];
$password = $_POST['password'];

// Validate and sanitize the user input
$username = filter_var($username, FILTER_SANITIZE_STRING);
$password = filter_var($password, FILTER_SANITIZE_STRING);

// Use LDAP escaping functions
$username = ldap_escape($username, '', LDAP_ESCAPE_FILTER);
$password = ldap_escape($password, '', LDAP_ESCAPE_FILTER);

$query = "(&(uid=" . $username . ")(userPassword=" . $password . "))";

$ds=ldap_connect("localhost");
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ds);

$sr=ldap_search($ds, "o=My Company, c=US", $query);
$info = ldap_get_entries($ds, $sr);
?>

The original code was vulnerable to LDAP injection attacks because it directly used user input in an LDAP query. An attacker could potentially manipulate the query to gain unauthorized access or retrieve sensitive information.

The fixed code mitigates this risk by implementing several security measures:

  1. Input Validation and Sanitization: The user input is sanitized using PHP's filter_var function with the FILTER_SANITIZE_STRING filter. This removes tags and encodes special characters, reducing the risk of injection attacks.

  2. LDAP Escaping: The user input is further secured using the ldap_escape function. This function escapes any special characters in the input that could potentially alter the LDAP query structure.

By implementing these measures, the code is now more secure and less susceptible to LDAP injection attacks. However, it's important to note that these measures alone may not completely eliminate the risk of LDAP injection. Additional security measures such as using parameterized queries, limiting LDAP account permissions, and implementing secure error handling should also be considered.

References