20

I am working on my first desktop app that queries LDAP. I'm working in C under unix and using opends, and I'm new to LDAP. After woking a while on that I noticed that the user could be able to alter the LDAP query by injecting malicious code.
I'd like to know which sanitizing techniques are known, not only for C/unix development but in more general terms, i.e., web development etc.
I thought that escaping equals and semicolons would be enough, but not sure.

Here is a little piece of code so I can make clearer the question:

 String ldapSearchQuery = "(cn=" + $userName + ")";
 System.out.println(ldapSearchQuery); 

Obviously I do need to sanitize $userName, as stated in this OWASP ARTICLE

mati
  • 5,218
  • 3
  • 32
  • 49
  • 2
    There's an RFC that talks about escaping LDAP search filters (http://www.ietf.org/rfc/rfc2254.txt), but it's not focused on security. However, it lists the following as requiring escaping: *()\ and NUL (0x00). So I would add the asterisk and backslash to your list. Couldn't find any really authoritative source for this topic. Not sure if there's some unicode angle you need to worry about, as well. Personally, I used a very restrictive white-list (digits, chars, underscore and space) approach on my implementation. – Sami Koivu Jun 13 '10 at 03:34
  • possible duplicate of [How to escape a string in C#, for use in an LDAP query](http://stackoverflow.com/questions/649149/how-to-escape-a-string-in-c-for-use-in-an-ldap-query) – Randolpho Jun 22 '10 at 14:03
  • @Randolpho: Thanks, I'd rather say related instead of duplicate. But thank you anyway, good question to take it as an extra reference (I did not see it before posting my question). – mati Jun 22 '10 at 14:44
  • @Matias: yes, definitely related. Duplicate is such a subjective term these days. :) – Randolpho Jun 22 '10 at 15:05

4 Answers4

12

OWASP is a good security guide that I use a lot, and has example code (in Java, but you should be able to translate): http://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java

Also, here's an Active Directory specific reference: http://www.rlmueller.net/CharactersEscaped.htm

Trueblood
  • 515
  • 2
  • 5
  • 11
3

You got your answer in the question comment, already. RFC 2254 has it.

Here's what I use in PHP. Something equivalent in your language should suffice.

/**
 * Sanitizes ldap search strings.
 * See rfc2254
 * @link http://www.faqs.org/rfcs/rfc2254.html
 * @since 1.5.1 and 1.4.5
 * @param string $string
 * @return string sanitized string
 * @author Squirrelmail Team
 */
function ldapspecialchars($string) {
    $sanitized=array('\\' => '\5c',
                     '*' => '\2a',
                     '(' => '\28',
                     ')' => '\29',
                     "\x00" => '\00');

    return str_replace(array_keys($sanitized),array_values($sanitized),$string);
}
Alexandros V
  • 560
  • 4
  • 11
3

And this is my C# translation of the escape functions in the blog mentioned by @TrueBlood.

/// <summary>
/// Escape a string for usage in an LDAP DN to prevent LDAP injection attacks.
/// There are certain characters that are considered special characters in a DN.
/// The exhaustive list is the following: ',','\','#','+','<','>',';','"','=', and leading or trailing spaces
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string EscapeForDN(string name)
{
    StringBuilder sb = new StringBuilder();

    if (name.Length > 0 && ((name[0] == ' ') || (name[0] == '#')))
    {
        sb.Append('\\'); // add the leading backslash if needed
    }

    for (int i = 0; i < name.Length; i++)
    {
        char curChar = name[i];
        switch (curChar)
        {
            case '\\':
                sb.Append(@"\\");
                break;
            case ',':
                sb.Append(@"\,");
                break;
            case '+':
                sb.Append(@"\+");
                break;
            case '"':
                sb.Append("\\\"");
                break;
            case '<':
                sb.Append(@"\<");
                break;
            case '>':
                sb.Append(@"\>");
                break;
            case ';':
                sb.Append(@"\;");
                break;
            default:
                sb.Append(curChar);
                break;
        }
    }

    if (name.Length > 1 && name[name.Length - 1] == ' ')
    {
        sb.Insert(sb.Length - 1, '\\'); // add the trailing backslash if needed
    }

    return sb.ToString();
}

/// <summary>
/// Escape a string for usage in an LDAP DN to prevent LDAP injection attacks.
/// </summary>
public static string EscapeForSearchFilter(string filter)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < filter.Length; i++)
    {
        char curChar = filter[i];
        switch (curChar)
        {
            case '\\':
                sb.Append("\\5c");
                break;
            case '*':
                sb.Append("\\2a");
                break;
            case '(':
                sb.Append("\\28");
                break;
            case ')':
                sb.Append("\\29");
                break;
            case '\u0000':
                sb.Append("\\00");
                break;
            default:
                sb.Append(curChar);
                break;
        }
    }
    return sb.ToString();
}
chtenb
  • 14,924
  • 14
  • 78
  • 116
0

If you are using Spring, there is a class LdapEncoder (https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/support/LdapEncoder.html) which provides methods for encoding values in a filter and DNs. This class is actually present in at least two spring libraries, spring-ldap-core and spring-security-ldap. And twice in the latter :)

lrxw
  • 3,576
  • 7
  • 32
  • 46