18

I have an LDAP query, which I am using to perform a search in C#. It uses two string variables (username and domain) which need to be escaped for security reasons.

How should I escape the strings? Is there a function available in C#.NET to do this?


Example LDAP search conditions :

(objectCategory=person)
(userprincipalname=username@domain*)
(samaccountname=username)

Example LDAP query string in C# :

string search = "(&(&(objectCategory=person)(userprincipalname=" 
        + username 
        + "@"
        + domain 
        + "*)(samaccountname=" 
        + username 
        + ")))";

Edit: I already have the LDAP query working, and returning results. All I want is to escape the parameters.

Sophia
  • 5,643
  • 9
  • 38
  • 43
  • Sophia, do you really need to apply the userprincipalname to the query? You could probably get by with just querying the domain and samaccountname. I seem to get get by fine by doing that. – matt_dev Mar 16 '09 at 04:46
  • I was wondering if I was doing that right - this is the first time I've used active directory. What do you mean by querying the domain? I'm getting the result out using a DirectorySearcher and SearchResult, the result doesn't seem to have any obvious property called domain or similar – Sophia Mar 16 '09 at 05:03
  • What do you mean escape the string? – CodeRedick Mar 16 '09 at 05:20
  • Replace all the special characters not permitted in the LDAP query with their escape sequences. Like the Server.UrlEncode() function, but for LDAP – Sophia Mar 16 '09 at 05:31
  • I can't believe this was not provided with core DirectoryServices :( – user2864740 Aug 09 '18 at 19:31

6 Answers6

34

The following is my translation from the Java code mentioned by Sophia into C#.

/// <summary>
/// Escapes the LDAP search filter to prevent LDAP injection attacks.
/// </summary>
/// <param name="searchFilter">The search filter.</param>
/// <see cref="https://blogs.oracle.com/shankar/entry/what_is_ldap_injection" />
/// <see cref="http://msdn.microsoft.com/en-us/library/aa746475.aspx" />
/// <returns>The escaped search filter.</returns>
private static string EscapeLdapSearchFilter(string searchFilter)
{
    StringBuilder escape = new StringBuilder(); // If using JDK >= 1.5 consider using StringBuilder
    for (int i = 0; i < searchFilter.Length; ++i)
    {
        char current = searchFilter[i];
        switch (current)
        {
            case '\\':
                escape.Append(@"\5c");
                break;
            case '*':
                escape.Append(@"\2a");
                break;
            case '(':
                escape.Append(@"\28");
                break;
            case ')':
                escape.Append(@"\29");
                break;
            case '\u0000':
                escape.Append(@"\00");
                break;
            case '/':
                escape.Append(@"\2f");
                break;
            default:
                escape.Append(current);
                break;
        }
    }

    return escape.ToString();
}
Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
Jeow Li Huan
  • 3,758
  • 1
  • 34
  • 52
6

I found a solution here, in a blog post about LDAP Injection

This solution involves adding your own function to escape the username and domain name, his solution is in Java, but the idea is there.

Also MSDN lists which special characters need to be replaced by escape sequences.

As far as I can tell there doesn't seem to be any method for escaping LDAP strings in System.DirectoryServices (like there is in HttpServerUtility for URLs etc)

Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
Sophia
  • 5,643
  • 9
  • 38
  • 43
4

Use AntiXss library from address: https://www.nuget.org/packages/AntiXss

string encoded = Microsoft.Security.Application.Encoder.LdapFilterEncode(input);
opis-kladno
  • 117
  • 5
  • 2
    This seems to be the best answer here but note it is considered end-of-life and is no longer being maintained https://archive.codeplex.com/?p=wpl – Matthew Aug 01 '18 at 18:31
  • Yeah, but the built in System.Web.Security.AntiXss.AntiXssEncoder encoder regrettably doesn't include the Encoder.LdapXxxEncode functions. – Flydog57 Oct 04 '18 at 20:49
2

Maybe let somebody else worry about it? See LINQtoAD.

Ðаn
  • 10,934
  • 11
  • 59
  • 95
  • That seems like overkill for just escaping a string? – Sophia Mar 16 '09 at 04:54
  • 2
    I think he's saying that LINQtoAD would be a better way to query AD overall. Just like you _could_ write straight SQL queries and then pull a dataset... but LINQtoSQL makes everything so much easier... – CodeRedick Mar 16 '09 at 05:20
  • Oh, I see. I already have the query to AD working with just two lines (using System.DirectoryServices methods), so I don't really need it - I'm not using AD anywhere else in my project. – Sophia Mar 16 '09 at 05:42
  • 1
    While normally agreeing on this and while Bart De Smet is an awfully clever guy, but in this exact case going LINQtoAD won't get you much in terms of added security against LDAP injections, since the the escaping in LINQtoAD goes a little something like this (well actually exactly something like this): val = val.ToString().Replace("(", "0x28").Replace(")", "0x29").Replace(@"\", "0x5c"); – veggerby Nov 09 '10 at 12:57
1

Are you trying to prevent some sort of injection attack against your directory server via user input? If that is the case I would just validate the input with Regex before passing it to LDAP.

Jason Jackson
  • 17,016
  • 8
  • 49
  • 74
  • The username and domain name shouldn't have any of the characters that need to be escaped in the first place: , \ # + < > ; " = – UncleO Mar 16 '09 at 05:35
  • "If any of the following special characters must appear in the search filter as literals, they must be replaced by the listed escape sequence." http://msdn.microsoft.com/en-us/library/aa746475.aspx – Sophia Mar 16 '09 at 06:04
  • LDAP query may involve email, which CAN contain '=', '+' and so on. – Victor Sergienko Jan 31 '13 at 12:04
0

Use PInvoke with DsQuoteRdnValueW. For code, see my answer to another question: https://stackoverflow.com/a/11091804/628981

Community
  • 1
  • 1
Sean Hall
  • 7,629
  • 2
  • 29
  • 44