一尘不染

如何验证域凭证?

c#

我想针对域控制器验证一组凭据。例如:

Username: STACKOVERFLOW\joel
Password: splotchy

方法1.使用模拟查询Active Directory

很多人建议在Active
Directory中查询某些内容。如果抛出异常,则说明凭据无效-如本stackoverflow问题所示

但是,这种方法有一些严重的缺点

  1. 您不仅在验证域帐户,而且还在进行隐式授权检查。也就是说,您正在使用模拟令牌从AD读取属性。如果原本有效的帐户无权读取广告怎么办?默认情况下,所有用户都具有读取访问权限,但是可以将域策略设置为禁用受限帐户(和/或组)的访问权限。

  2. 与AD绑定会产生严重的开销,必须在客户端上加载AD模式缓存(DirectoryServices使用的ADSI提供程序中的ADSI缓存)。这既是网络,又是AD服务器,都非常耗资源-对于简单的操作(如验证用户帐户)而言,费用太高。

  3. 对于非例外情况,您要依靠例外失败,并假设这意味着无效的用户名和密码。其他问题(例如,网络故障,AD连接故障,内存分配错误等)随后会误认为身份验证失败。

方法2。LogonUser Win32 API

其他人建议使用LogonUser()API函数。这听起来不错,但不幸的是,调用用户有时有时需要通常仅授予操作系统本身的权限:

调用LogonUser的进程需要SE_TCB_NAME特权。如果调用过程没有此特权,则LogonUser失败,并且GetLastError返回ERROR_PRIVILEGE_NOT_HELD。

在某些情况下,调用LogonUser的过程还必须启用SE_CHANGE_NOTIFY_NAME特权;否则,LogonUser失败,并且GetLastError返回ERROR_ACCESS_DENIED。本地系统帐户或属于管理员组的帐户不需要此特权。默认情况下,SE_CHANGE_NOTIFY_NAME为所有用户启用,但是某些管理员可能为所有人禁用它。

发放“ 充当操作系统的一部分 ”特权并不是您要随意地做的事-
正如Microsoft在知识库文章中指出的那样:

…正在调用LogonUser的进程必须具有SE_TCB_NAME特权(在用户管理器中,这是“ 充当操作系统的一部分
”权限)。SE_TCB_NAME特权非常强大, 不应仅授予任意用户一个 特权 ,以便他们可以运行 需要验证凭据 的应用程序

此外,LogonUser()如果指定了空白密码,则对的调用将失败。


验证一组域凭据的正确方法是什么?


碰巧 是从托管代码调用的,但这是Windows的一个普遍问题。可以假定客户安装了.NET Framework 2.0。


阅读 566

收藏
2020-05-19

共1个答案

一尘不染

使用System.DirectoryServices.AccountManagement的 .NET 3.5中的C#。

 bool valid = false;
 using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
 {
     valid = context.ValidateCredentials( username, password );
 }

这将针对当前域进行验证。检出参数化的PrincipalContext构造函数以获取其他选项。

2020-05-19