Frage

I am currently properly escaping my filters, either using Spring LDAP Filter clases, or by going through LdapEncoder.filterEncode().

At the same time, I am using WireShark to capture packets being exchanged between my local machine and the LDAP server.

And I seem to have a problem. Even if I properly escape values (which I have confirmed through debugging), they come out unescaped through the network. I have also confirmed (through debugging) that the value stays encoded all the way until it enters javax.naming.InitialContext.

Here is an example (note that I am using Spring LDAP 1.3.0, and that these happen on both Oracle JDK 6u45 and Oracle JDK 7u45).

In my own code, on the service layer, the call being made is:

     String lMailAddress = (String) ldapTemplate.searchForObject("", new EqualsFilter(ldapUserSearchFilterAttribute, principal).encode(), new ContextMapper() {
                @Override
                public Object mapFromContext(Object ctx) {
                    DirContextAdapter lContext = (DirContextAdapter) ctx;
                    return lContext.getStringAttribute("mail");
                }});

At this point, I can confirm that the String returned by the encode() method on the filter is "(sAMAccountName=boi\2a)"

The last point I can debug the code is the following one (starts at line 229 of org.springframework.ldap.core.LdapTemplate):

SearchExecutor se = new SearchExecutor() {
            public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException {
                return ctx.search(base, filter, controls);
            }
        };

When executeSearch() is later invoked, I can also verify that the filter String contains "(sAMAccountName=boi\2a)".

I cannot debug any further, since I do not have the source code to javax,naming.* or com.sun.jndi.ldap.* (since com.sun.jndi.ldap.LdapCtx is being invoked).

However, as soon as the call returns from executeSearch(), WireShark informs me that an LDAP packet containing a searchRequest with the filter "(sAMAccountName=boi*)" has been transmitted (the * is no longer escaped).

I have used similar encoding and used different methods of LdapTemplate that yielded the result I was expecting (I saw the encoded filter being transmitted in WireShark), but I cannot explain why, in the case I just exposed, the value gets decoded before being transmitted.

Please help me understanding the situation. Hpoefully, I am the one who does not properly understand the LDAP protocol here.

Thanks.

Disclaimer: I have posted the same question to Spring LDAP forums.

TL/DR: Why is com.sun.jndi.ldap.LdapCtx decoding LDAP encoded filters (like \2a to *) before transmitting them to the LDAP server?

Update: Tried and observed the same behavior with IBM's J9 JDK7.

War es hilfreich?

Lösung

Although I'm not familiar with Spring LDAP, it doesn't sound like there's necessarily a reason to be concerned. LDAP filters aren't transmitted as clear text, but rather in a binary encoding, and there is no need for escaping in this mechanism (nor would it be correct to do so).

Let's take "(sAMAccountName=boi*)" as an example. As written, this filter is a substring filter with a subInitial component of "boi". As you point out, if you want it to be an equality filter rather than a substring filter, then the string representation would have to be "(sAMAccountName=boi\2a)". However, the binary encodings for these filters don't use any escaping, but instead use an ASN.1 BER type to differentiate between substring and equality filters.

If you want "(sAMAccountName=boi*)" as a substring filter, then the encoded representation would be:

 a417040e73414d4163636f756e744e616d6530058003626f69

On the other hand, if you want "(sAMAccountName=boi\2a)" as an equality filter, the encoding would be:

 a316040e73414d4163636f756e744e616d650404626f692a

The full explanation of the encoding isn't something I want to get into, but the "a4" at the beginning of the first one indicates that it's a substring filter, whereas the "a3" at the beginning of the second indicates that it's an equality filter.

You should be able to verify the actual bytes sent in WireShark. It may well be that WireShark doesn't properly escape the filter when generating the string representation, but that would be an issue with WireShark itself. The directory server only gets the binary representation, and it's hard to believe that an LDAP server would misinterpret that.

Andere Tipps

OWASP suggest to encode strings for searches:

public static final String escapeLDAPSearchFilter(String filter) {
   StringBuffer sb = new StringBuffer(); // If using JDK >= 1.5 consider using StringBuilder
   for (int i = 0; i < filter.length(); i++) {
       char curChar = filter.charAt(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);
       }
   }
   return sb.toString();

}

DN strings are escaped different. See the link below.

https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java

The best way is to use parameterized filter search method, thus the parameter will be properly encoded.

See https://docs.oracle.com/javase/jndi/tutorial/ldap/search/search.html

// Perform the search
NamingEnumeration answer = ctx.search("ou=NewHires", 
    "(&(mySpecialKey={0}) (cn=*{1}))",      // Filter expression
    new Object[]{key, name},                // Filter arguments
    null);                  // Default search controls
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top