CodeQL 文档

从用户控制的来源构建的 LDAP 查询

ID: cs/ldap-injection
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-090
Query suites:
   - csharp-code-scanning.qls
   - csharp-security-extended.qls
   - csharp-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

如果使用字符串连接构建 LDAP 查询,并且连接的组件包含用户输入,则用户很可能能够运行恶意 LDAP 查询。

建议

如果必须在 LDAP 查询中包含用户输入,则应对其进行转义,以避免恶意用户提供更改查询含义的特殊字符。如果可能,请使用现有的库,例如 AntiXSS 库。

示例

在以下示例中,代码接受用户提供的“组织名称”和“用户名”,并使用它们查询 LDAP 以访问“类型”属性。

第一个示例将未经验证和未编码的用户输入直接连接到用于 LDAP 查询的 DN(可分辨名称)和搜索过滤器中。恶意用户可以提供特殊字符来更改这些查询的含义,并搜索完全不同的一组值。

第二个示例使用 Microsoft AntiXSS 库对用户值进行编码,然后再将它们包含在 DN 和搜索过滤器中。这确保了恶意用户无法更改查询的含义。

using Microsoft.Security.Application.Encoder
using System;
using System.DirectoryServices;
using System.Web;

public class LDAPInjectionHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext ctx)
    {
        string userName = ctx.Request.QueryString["username"];
        string organizationName = ctx.Request.QueryString["organization_name"];
        // BAD: User input used in DN (Distinguished Name) without encoding
        string ldapQuery = "LDAP://myserver/OU=People,O=" + organizationName;
        using (DirectoryEntry root = new DirectoryEntry(ldapQuery))
        {
            // BAD: User input used in search filter without encoding
            DirectorySearcher ds = new DirectorySearcher(root, "username=" + userName);

            SearchResult result = ds.FindOne();
            if (result != null)
            {
                using (DirectoryEntry user = result.getDirectoryEntry())
                {
                    ctx.Response.Write(user.Properties["type"].Value)
                }
            }
        }

        // GOOD: Organization name is encoded before being used in DN
        string safeOrganizationName = Encoder.LdapDistinguishedNameEncode(organizationName);
        string safeLDAPQuery = "LDAP://myserver/OU=People,O=" + safeOrganizationName;
        using (DirectoryEntry root = new DirectoryEntry(safeLDAPQuery))
        {
            // GOOD: User input is encoded before being used in search filter
            string safeUserName = Encoder.LdapFilterEncode(userName);
            DirectorySearcher ds = new DirectorySearcher(root, "username=" + safeUserName);

            SearchResult result = ds.FindOne();
            if (result != null)
            {
                using (DirectoryEntry user = result.getDirectoryEntry())
                {
                    ctx.Response.Write(user.Properties["type"].Value)
                }
            }
        }
    }
}

参考

  • ©GitHub 公司
  • 条款
  • 隐私