AD系列之九十三:检查是否支持LDAP匿名读取
AD系列之九十三:检查是否支持LDAP匿名读取

AD系列之九十三:检查是否支持LDAP匿名读取

一、使用LDAP客户端工具直接测试

这是最可靠的方法。你可以使用Windows自带的 ldp.exe 工具来模拟连接

操作步骤

  1. 按 Win + R,输入 ldp 并回车,打开工具。
  2. 点击 “连接” -> “连接”
  3. 输入你的AD服务器地址(如 ad-server.yourdomain.com),端口保持 389(LDAP)或 636(LDAPS),点击“确定”。
  4. 连接成功后,点击 “连接” -> “绑定”
  5. 在弹出的对话框中,不填写任何用户和密码,直接点击“确定”。

显示如下:

ld = ldap_open("xjg-dc08.sailuntire.com", 389);
Established connection to xjg-dc08.sailuntire.com.
Retrieving base DSA information...
Getting 1 entries:
Dn: (RootDSE)
configurationNamingContext: CN=Configuration,DC=sailuntire,DC=com; 
currentTime: 2025/12/12 13:27:39 中国标准时间; 
defaultNamingContext: DC=sailuntire,DC=com; 
dnsHostName: XJG-DC08.sailuntire.com; 
domainControllerFunctionality: 7 = ( WIN2016 ); 
domainFunctionality: 6 = ( WIN2012R2 ); 
dsServiceName: CN=NTDS Settings,CN=XJG-DC08,CN=Servers,CN=XJG,CN=Sites,CN=Configuration,DC=sailuntire,DC=com; 
forestFunctionality: 6 = ( WIN2012R2 ); 
highestCommittedUSN: 41371320; 
isGlobalCatalogReady: TRUE; 
isSynchronized: TRUE; 
ldapServiceName: sailuntire.com:xjg-dc08$@SAILUNTIRE.COM; 
namingContexts (5): DC=sailuntire,DC=com; CN=Configuration,DC=sailuntire,DC=com; CN=Schema,CN=Configuration,DC=sailuntire,DC=com; DC=DomainDnsZones,DC=sailuntire,DC=com; DC=ForestDnsZones,DC=sailuntire,DC=com; 
rootDomainNamingContext: DC=sailuntire,DC=com; 
schemaNamingContext: CN=Schema,CN=Configuration,DC=sailuntire,DC=com; 
serverName: CN=XJG-DC08,CN=Servers,CN=XJG,CN=Sites,CN=Configuration,DC=sailuntire,DC=com; 
subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,DC=sailuntire,DC=com; 
supportedCapabilities (6): 1.2.840.113556.1.4.800 = ( ACTIVE_DIRECTORY ); 1.2.840.113556.1.4.1670 = ( ACTIVE_DIRECTORY_V51 ); 1.2.840.113556.1.4.1791 = ( ACTIVE_DIRECTORY_LDAP_INTEG ); 1.2.840.113556.1.4.1935 = ( ACTIVE_DIRECTORY_V61 ); 1.2.840.113556.1.4.2080 = ( ACTIVE_DIRECTORY_V61_R2 ); 1.2.840.113556.1.4.2237 = ( ACTIVE_DIRECTORY_W8 ); 
supportedControl (40): 1.2.840.113556.1.4.319 = ( PAGED_RESULT ); 1.2.840.113556.1.4.801 = ( SD_FLAGS ); 1.2.840.113556.1.4.473 = ( SORT ); 1.2.840.113556.1.4.528 = ( NOTIFICATION ); 1.2.840.113556.1.4.417 = ( SHOW_DELETED ); 1.2.840.113556.1.4.619 = ( LAZY_COMMIT ); 1.2.840.113556.1.4.841 = ( DIRSYNC ); 1.2.840.113556.1.4.529 = ( EXTENDED_DN ); 1.2.840.113556.1.4.805 = ( TREE_DELETE ); 1.2.840.113556.1.4.521 = ( CROSSDOM_MOVE_TARGET ); 1.2.840.113556.1.4.970 = ( GET_STATS ); 1.2.840.113556.1.4.1338 = ( VERIFY_NAME ); 1.2.840.113556.1.4.474 = ( RESP_SORT ); 1.2.840.113556.1.4.1339 = ( DOMAIN_SCOPE ); 1.2.840.113556.1.4.1340 = ( SEARCH_OPTIONS ); 1.2.840.113556.1.4.1413 = ( PERMISSIVE_MODIFY ); 2.16.840.1.113730.3.4.9 = ( VLVREQUEST ); 2.16.840.1.113730.3.4.10 = ( VLVRESPONSE ); 1.2.840.113556.1.4.1504 = ( ASQ ); 1.2.840.113556.1.4.1852 = ( QUOTA_CONTROL ); 1.2.840.113556.1.4.802 = ( RANGE_OPTION ); 1.2.840.113556.1.4.1907 = ( SHUTDOWN_NOTIFY ); 1.2.840.113556.1.4.1948 = ( RANGE_RETRIEVAL_NOERR ); 1.2.840.113556.1.4.1974 = ( FORCE_UPDATE ); 1.2.840.113556.1.4.1341 = ( RODC_DCPROMO ); 1.2.840.113556.1.4.2026 = ( DN_INPUT ); 1.2.840.113556.1.4.2064 = ( SHOW_RECYCLED ); 1.2.840.113556.1.4.2065 = ( SHOW_DEACTIVATED_LINK ); 1.2.840.113556.1.4.2066 = ( POLICY_HINTS_DEPRECATED ); 1.2.840.113556.1.4.2090 = ( DIRSYNC_EX ); 1.2.840.113556.1.4.2205 = ( UPDATE_STATS ); 1.2.840.113556.1.4.2204 = ( TREE_DELETE_EX ); 1.2.840.113556.1.4.2206 = ( SEARCH_HINTS ); 1.2.840.113556.1.4.2211 = ( EXPECTED_ENTRY_COUNT ); 1.2.840.113556.1.4.2239 = ( POLICY_HINTS ); 1.2.840.113556.1.4.2255 = ( SET_OWNER ); 1.2.840.113556.1.4.2256 = ( BYPASS_QUOTA ); 1.2.840.113556.1.4.2309 = ( LINK_TTL ); 1.2.840.113556.1.4.2330; 1.2.840.113556.1.4.2354; 
supportedLDAPPolicies (21): MaxPoolThreads; MaxPercentDirSyncRequests; MaxDatagramRecv; MaxReceiveBuffer; MaxPreAuthReceiveBuffer; InitRecvTimeout; MaxConnections; MaxConnIdleTime; MaxPageSize; MaxBatchReturnMessages; MaxQueryDuration; MaxDirSyncDuration; MaxTempTableSize; MaxResultSetSize; MinResultSets; MaxResultSetsPerConn; MaxNotificationPerConn; MaxValRange; MaxValRangeTransitive; ThreadMemoryLimit; SystemMemoryLimitPercent; 
supportedLDAPVersion (2): 3; 2; 
supportedSASLMechanisms (4): GSSAPI; GSS-SPNEGO; EXTERNAL; DIGEST-MD5; 

根据你提供的 ldp.exe 日志来看,网络连接和基本信息查询是“通了”,但这并不意味着你的AD服务器已开启完整的LDAP匿名读取权限。

日志显示,你已成功连接到 xjg-dc11.sailuntire.com 的389端口,并匿名查询到了 RootDSE 信息。这说明:

  1. 网络连通:LDAP服务(389端口)可达。
  2. 基础信息可获取:服务器默认会向任何连接者公开RootDSE信息,它相当于目录服务的“名片”,包含了关键的配置信息,例如:
    • defaultNamingContext: DC=sailuntire,DC=com → 这是你后续集成时需要填写的 Base DN
    • domainControllerFunctionality: 7 = ( WIN2016 ) → 域控操作系统是Windows Server 2016。
    • supportedLDAPVersion: 3; 2 → 支持LDAP v3协议。
    • namingContexts → 列出了目录中所有的命名上下文(分区)。

❗ 但这不意味着匿名读取已开启

在Active Directory中,匿名访问RootDSE是微软默认允许的例外情况,主要是为了兼容性和服务发现。这不代表你可以匿名搜索用户、查询组信息或读取其他任何目录对象。

要真正测试匿名读取权限,你需要继续以下关键步骤:

🔍 继续测试:验证匿名绑定与搜索

在 ldp.exe 连接成功(显示以上日志)后,请按顺序操作:

  1. 尝试匿名绑定
    • 点击菜单栏的 “连接” (Connection) -> “绑定” (Bind)…
    • 在弹出的对话框中,确保不填写“用户”(User)和“密码”(Password),绑定类型选择 “简单绑定”(Simple bind)
    • 点击“确定”。
    • 观察结果
res = ldap_simple_bind_s(ld, '', <unavailable>); // v.3
Authenticated as: 'NT AUTHORITY\ANONYMOUS LOGON'.
  1. 尝试匿名搜索(最关键的一步):
    • 在成功绑定(或不绑定直接尝试)后,点击 “浏览” (Browse) -> “搜索” (Search)…
    • 在搜索对话框中输入:
      • Base DN:填写从上面日志中获取的 DC=sailuntire,DC=com
      • Filter:输入 (objectClass=*) 或 (sAMAccountName=*)
      • 点击“运行”。
    • 观察结果
-----------
***Searching...
ldap_search_s(ld, "DC=sailuntire,DC=com", 1, "(objectclass=*)", attrList,  0, &msg)
Error: Search: 操作错误. <1>
Server error: 000004DC: LdapErr: DSID-0C090D10, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4f7c
Error 0x4DC 因为用户还未通过身份验证,不能执行所要求的操作。
Result <1>: 000004DC: LdapErr: DSID-0C090D10, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4f7c
Getting 0 entries:
-----------

这个错误信息给出了最终且明确的结论:你的AD域控 xjg-dc11.sailuntire.com 出于安全考虑,已正确禁止了LDAP匿名读取

🔍 错误信息解读

错误的核心部分是:

In order to perform this operation a successful bind must be completed on the connection.
(为了执行此操作,必须在连接上完成一个成功的绑定。)

这个“成功的绑定”是指一个经过身份验证的绑定(例如使用域账号和密码),而不是你之前做的那个名义上的“匿名绑定”。

整个过程的逻辑是

  1. ✅ 匿名连接被允许:你可以连接到服务器的389端口。
  2. ✅ RootDSE信息可查询:你可以匿名读取服务器的基本信息(defaultNamingContext 等)。
  3. ❌ 实质性操作被拒绝:当你试图执行搜索用户((objectclass=user))这类触及目录数据的操作时,服务器会立即阻止,并给出上述错误。

💎 结论与应用集成影响

这证实了你的AD环境是安全且符合最佳实践的。现代Windows Server(尤其是2012 R2及以上版本)默认就是此配置。

对你的直接影响

  • 你的应用系统集成,仅填写服务器地址(xjg-dc11.sailuntire.com:389)是绝对无法完成认证的。
  • 应用必须提供一个有效的域账号凭据(Bind DN和密码)来与AD建立已验证的连接,之后才能搜索和验证用户。

✅ 下一步操作:正确配置应用

你现在需要收集以下信息并填入应用系统的LDAP/AD集成配置界面:

配置项需要填入的值(根据你的环境)说明与如何获取
服务器/主机名xjg-dc11.sailuntire.com你已知道。
端口389默认LDAP端口。若需加密可使用 636 (LDAPS)。
Base DNDC=sailuntire,DC=com从之前查询的 defaultNamingContext 直接获得。
绑定DN / 服务账号例如:CN=ldap_bind,CN=Users,DC=sailuntire,DC=com关键! 需要域管理员创建一个专用只读域账号
绑定密码********上述账号的密码。
用户绑定格式%username%@sailuntire.com通常使用UPN格式。或sAMAccountName格式,取决于用户登录名。
用户搜索库通常与Base DN相同,或指定OU,如OU=Users,DC=sailuntire,DC=com指定从哪个组织单位开始搜索用户,可缩小范围。
用户名字段通常为 sAMAccountName 或 userPrincipalName与“用户绑定格式”对应。

📝 具体行动建议

  1. 联系你的域管理员,提供以下明确需求:“我们需要一个专用的域账号,用于应用系统通过LDAP协议集成AD认证。该账号只需对 DC=sailuntire,DC=com 下的用户对象(或指定OU)拥有 ‘读取’ 权限,用于绑定和搜索用户即可。”
  2. 获取上述配置信息后,完整填写到你的应用系统设置中。
  3. 配置完成后,可以再次使用 ldp.exe,但这次使用服务账号进行绑定(在“绑定”对话框中填写完整的Bind DN和密码),绑定成功后,再执行相同的搜索测试,应该就能正常返回用户列表了。

简单来说,你的AD服务器是安全的,现在的问题焦点从“AD是否允许匿名”转移到了“如何正确配置应用使用服务账号进行认证”。如果你在配置应用时需要进一步帮助,可以告诉我应用的名称或配置界面截图。

⚙️ 方法二:检查AD域控的安全策略

匿名访问权限由AD的高级安全设置控制,你可以使用 adsiedit.msc 工具查看。

操作路径

  1. 打开 adsiedit.msc
  2. 连接到 “配置”
  3. 导航到路径:DC=yourdomain,DC=com -> CN=System -> CN=Services -> CN=Windows NT -> CN=Directory Service
  4. 在右侧找到名为 CN=Directory Service 的对象,右键打开其 “属性”
  5. 查找名为 dsHeuristics 的属性。
    • 如果此属性不存在或值为空,则遵循默认行为。对于现代Windows Server(如2016及以上),默认是禁止匿名读取的
    • 如果此属性存在,其值是一个长字符串。其中 前两位字符 至关重要。如果第一位是 2 (例如 2000000...),则表示 “允许匿名读取除特定敏感属性外的所有信息”。这是允许匿名访问的关键标志。

📊 方法三:检查事件日志

在AD服务器上打开 “事件查看器”,筛选 安全日志 或 目录服务日志,在匿名访问尝试前后的事件中,可能会找到相关审核事件(如事件ID为2886、2889等的事件),其中会包含访问令牌为 ANONYMOUS LOGON 的记录。

💡 重要提醒与安全建议

综合来看,根据当前资料,绝大多数现代AD环境出于安全考虑,默认是禁止LDAP匿名读取的。启用匿名访问会暴露用户、组等目录信息,带来安全风险

如果你的应用因集成需要匿名读取,更安全的做法是创建一个专用的、权限受限的域账号,在应用配置中使用该账号(Bind DN和密码)进行绑定和搜索,而不是依赖不安全的匿名访问

如果你在测试中绑定时得到了明确的错误代码,或者需要进一步分析 dsHeuristics 属性的配置,我可以为你提供更具体的分析。