如何使用LdapConnection修改nTSecurityDescriptor/DACL/ACL
使用
LdapConnection修改nTSecurityDescriptor/DACL/ACL实现方案 你用ModifyRequest直接修改失败,核心原因是两个:一是nTSecurityDescriptor是二进制格式的结构化属性,不能随便传值;二是LDAP修改安全描述符需要附加专属控制,缺了就会被服务端拒绝。
不需要绕回DirectoryEntry做认证,安全描述符的构造、序列化完全可以用官方类单独处理,和你用客户端证书认证的LdapConnection不冲突。
核心实现逻辑
- 安全描述符的序列化/反序列化直接用
ActiveDirectorySecurity类即可,这个类只负责SD结构的处理,不依赖ADSI的认证链路,不会和你现有证书认证的逻辑冲突,比手动拼二进制、转SDDL稳得多。 - 修改请求必须附加
SdFlagsControl,告诉AD服务端你要修改的是SD的哪个部分,否则哪怕账号有权限也会返回报错。 - 不要直接全量覆盖SD,先查询目标对象现有SD,在原有基础上修改DACL/ACL,避免误删所有者、继承权限等系统保留配置。
具体操作步骤
- 查询目标对象的现有
nTSecurityDescriptor属性:构造Base级别的搜索请求,只拉取nTSecurityDescriptor属性值,拿到原始字节数组。 - 把原始字节反序列化为
ActiveDirectorySecurity对象,调用其内置的AddAccessRule/RemoveAccessRule/ModifyAccessRule方法调整DACL/ACL,操作逻辑和你之前用DirectoryEntry时完全一致。 - 把修改后的安全描述符序列化为二进制字节,构造
ModifyRequest时用Replace操作替换nTSecurityDescriptor属性值,同时给请求附加SdFlagsControl,指定要修改的段为DACL。 - 直接用已经完成客户端证书认证的
LdapConnection实例发送请求即可。
可直接参考的代码片段
// 替换为你的目标对象DN string targetDn = "CN=TestObject,OU=Users,DC=domain,DC=com"; // 1. 查询现有安全描述符 var searchRequest = new SearchRequest( targetDn, "(objectClass=*)", SearchScope.Base, "nTSecurityDescriptor" ); var searchResponse = (SearchResponse)ldapConnection.SendRequest(searchRequest); var originalSdBytes = (byte[])searchResponse.Entries[0].Attributes["nTSecurityDescriptor"][0]; // 2. 反序列化并修改DACL,示例为给指定账号加读属性权限 var adSecurity = new ActiveDirectorySecurity(); adSecurity.SetSecurityDescriptorBinaryForm(originalSdBytes); var newAccessRule = new ActiveDirectoryAccessRule( identity: new NTAccount("DOMAIN", "targetUser"), adRights: ActiveDirectoryRights.ReadProperty, type: AccessControlType.Allow, objectType: Guid.Empty, inheritanceType: ActiveDirectorySecurityInheritance.All ); adSecurity.AddAccessRule(newAccessRule); // 3. 构造修改控制和修改请求 var modifiedSdBytes = adSecurity.GetSecurityDescriptorBinaryForm(); var sdControl = new SdFlagsControl( flags: SecurityMasks.Dacl | SecurityMasks.DiscretionaryInfoAcl, isCritical: true ); var modifyRequest = new ModifyRequest( targetDn, DirectoryAttributeOperation.Replace, "nTSecurityDescriptor", modifiedSdBytes ); modifyRequest.Controls.Add(sdControl); // 4. 提交修改 ldapConnection.SendRequest(modifyRequest);
常见踩坑说明
- 如果需要修改SACL,要确保你绑定的证书对应账号持有
SeSecurityPrivilege权限,同时SdFlagsControl的flags参数要加上SecurityMasks.Sacl。 - 不要手动拼接SD二进制或者自己解析SDDL,AD对SD的字节对齐、权限位校验非常严格,用官方
ActiveDirectorySecurity序列化是出错概率最低的方案。 - 如果返回权限不足错误,先排查两点:一是证书对应账号对目标对象是否有
WriteDacl权限,二是SdFlagsControl是否正确附加到了修改请求上,漏加控制是最常见的报错原因。
内容的提问来源于stack exchange,提问作者AndrewNo
相关产品推荐
相关产品推荐

