LDAP查询必须参数化且禁用匿名绑定,强制LDAPS签名,禁用NTLM,收紧权限,并启用审计日志与SIEM实时告警。
LDAP 查询字符串必须严格参数化,不能拼接用户输入
直接把用户名、邮箱等前端传入的值用 + 或 format() 拼进 ldap 查询字符串(如 "(samaccountname=" + user_input + ")"),等于给攻击者开了执行通道。一旦输入 admin)(|(uid=*)) 这类恶意 payload,就可能绕过认证或批量拖库。
正确做法是使用语言原生支持的参数化绑定接口:
- Java 用
LdapContext#search()的String[]参数形式,不拼接String查询语句 - Python 的
ldap3.Connection.search()必须通过filter_format或传入预编译 filter 字典,避免f"(cn={user_input})" - .NET 的
DirectorySearcher.Filter属性赋值前,用Regex.Replace(userInput, @"[^\w\s@.-]", "")做最小化白名单清洗(仅当无法用参数化时兜底)
域控制器上禁用匿名绑定并限制 LDAP 端口暴露面
默认 Windows 域控允许匿名 LDAP 绑定(ldap://dc01.example.com:389),攻击者无需凭据就能执行 baseDN 范围内的搜索,查出所有 OU、组策略链接甚至用户 hash(若启用了 msDS-ResultantPSO 等高危属性)。
必须立即执行以下操作:
- 在域控组策略中启用
Network security: LDAP client signing requirements并设为Require signing - 通过
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v "LDAPServerIntegrity" /t REG_DWORD /d 2 /f强制 LDAPS(636)或带签名的 LDAP(389) - 防火墙封禁面向公网/非信任网段的
389和636端口,内网也应按需开通 ACL,禁止开发测试机直连 DC
禁用 NTLM 认证并收缩 GPO 中的 LDAP 查询权限
NTLM 协议本身不加密 LDAP 查询内容,中间人可截获明文 filter;更危险的是,很多旧版应用(如某些监控工具、备份软件)硬编码了 Administrator 账户去连 LDAP,密码一旦泄露,整个域就失守。
加固要点很具体:
- 用
gpresult /h report.html检查所有 GPO 是否含LDAP://类脚本调用,改用Get-ADUser等 PowerShell 模块(自动走 Kerberos+加密通道) - 将应用使用的域账号加入
Protected Users组,该组成员禁止使用 NTLM、不缓存凭据、强制 AES 加密 - 对必须用 LDAP 查询的应用账号,在
Active Directory Users and Computers中右键属性 →Security选项卡,移除其对userPassword、unicodePwd、msDS-AllowedToDelegateTo等敏感属性的读取权限
启用 LDAP 审计日志并配置实时告警规则
不记录就等于没防御。Windows 默认只记失败登录,而 LDAP 注入往往伴随大量异常 filter(如含 *、(|、& 的长查询),这些在安全日志里对应事件 ID 4662(对象访问)和 5136(目录服务更改)。
必须做三件事:
- 在域控上运行
auditpol /set /category:"Directory Service Access" /success:enable /failure:enable - 用
wevtutil sl "Security" /q:true确认日志最大尺寸 ≥ 1GB,避免覆盖关键记录 - 在 SIEM(如 Elastic Stack、Splunk)中建规则:5 分钟内出现 ≥ 10 条含
Filter:字段且含*或括号嵌套深度 > 2 的EventID 4662日志,立即触发邮件/企微告警
真正难的是 filter 解析逻辑——很多 SIEM 默认不解析 LDAP filter 结构,得自己写 Grok 模式或用 Winlogbeat 的 ldap_filter 解码器,否则告警全是噪音。

















