【问题标题】:Java decoding encoded LDAP filters before transmitting? Preventing LDAP injectionsJava在传输之前解码编码的LDAP过滤器?防止 LDAP 注入
【发布时间】:2013-10-26 05:05:10
【问题描述】:

我目前正在正确地转义我的过滤器,或者使用 Spring LDAP 过滤器类,或者通过 LdapEncoder.filterEncode()。

同时,我正在使用 WireShark 来捕获在我的本地计算机和 LDAP 服务器之间交换的数据包。

而且我似乎有问题。即使我正确地转义了值(我已通过调试确认),它们也会通过网络未转义。我还确认(通过调试)该值一直保持编码,直到它进入 javax.naming.InitialContext。

这是一个示例(请注意,我使用的是 Spring LDAP 1.3.0,并且这些都发生在 Oracle JDK 6u45 和 Oracle JDK 7u45 上)。

在我自己的代码中,在服务层上,正在进行的调用是:

     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");
                }});

至此,我可以确认filter上encode()方法返回的String是“(sAMAccountName=boi\2a)”

我可以调试代码的最后一点是以下(从 org.springframework.ldap.core.LdapTemplate 的第 229 行开始):

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

稍后调用 executeSearch() 时,我还可以验证过滤器字符串是否包含“(sAMAccountName=boi\2a)”。

我无法进一步调试,因为我没有 javax,naming.* 或 com.sun.jndi.ldap.* 的源代码(因为正在调用 com.sun.jndi.ldap.LdapCtx)。

但是,一旦调用从 executeSearch() 返回,WireShark 就会通知我包含带有过滤器“(sAMAccountName=boi*)”的 searchRequest 的 LDAP 数据包已被传输(* 不再转义)。

我使用了类似的编码并使用了不同的 LdapTemplate 方法,产生了我期望的结果(我看到编码过滤器在 WireShark 中传输),但我无法解释为什么在我刚刚公开的情况下,值被解码在被传输之前。

请帮助我了解情况。不幸的是,我是一个没有正确理解 LDAP 协议的人。

谢谢。

免责声明:我已将相同的问题发布到 Spring LDAP 论坛。

TL/DR:为什么 com.sun.jndi.ldap.LdapCtx 在将 LDAP 编码过滤器(如 \2a 到 *)解码到 LDAP 服务器之前?

更新:用 IBM 的 J9 JDK7 尝试并观察到相同的行为。

【问题讨论】:

    标签: java security spring-security ldap spring-ldap


    【解决方案1】:

    虽然我不熟悉 Spring LDAP,但听起来没有必要担心。 LDAP 过滤器不是以明文形式传输的,而是以二进制编码的形式传输的,并且在这种机制中不需要转义(这样做也不正确)。

    我们以“(sAMAccountName=boi*)”为例。如所写,此过滤器是一个子字符串过滤器,其 subInitial 组件为“boi”。正如您所指出的,如果您希望它是一个相等过滤器而不是一个子字符串过滤器,那么字符串表示必须是“(sAMAccountName = boi \ 2a)”。但是,这些过滤器的二进制编码不使用任何转义,而是使用 ASN.1 BER 类型来区分子字符串和相等过滤器。

    如果您希望将“(sAMAccountName=boi*)”作为子字符串过滤器,则编码表示为:

     a417040e73414d4163636f756e744e616d6530058003626f69
    

    另一方面,如果您希望 "(sAMAccountName=boi\2a)" 作为等式过滤器,则编码为:

     a316040e73414d4163636f756e744e616d650404626f692a
    

    编码的完整解释不是我想深入的,但是第一个开头的“a4”表示它是一个子字符串过滤器,而第二个开头的“a3”表示这是一个平等过滤器。

    您应该能够验证在 WireShark 中发送的实际字节。很可能是 WireShark 在生成字符串表示时没有正确地转义过滤器,但这可能是 WireShark 本身的问题。目录服务器只获取二进制表示,很难相信 LDAP 服务器会误解它。

    【讨论】:

    • 正确。我截取的确实是一个等式 (3) 过滤器。我知道不会进行“子字符串”搜索(也不会进行注入)。谢谢! (为了记录,你是对的:a316040e73414d4163636f756e744e616d650404626f692a)
    【解决方案2】:

    OWASP 建议对搜索字符串进行编码:

    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 字符串转义不同。请参阅下面的链接。

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

    【讨论】:

      【解决方案3】:

      最好的方法是使用参数化过滤搜索方法,这样参数将被正确编码。

      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
      

      【讨论】:

        猜你喜欢
        • 2011-03-03
        • 2023-04-06
        • 1970-01-01
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 2022-07-27
        • 2023-03-08
        • 2020-03-21
        相关资源
        最近更新 更多