【发布时间】:2010-09-24 12:26:20
【问题描述】:
我想针对域控制器验证一组凭据。例如:
Username: STACKOVERFLOW\joel
Password: splotchy
方法一、模拟查询Active Directory
>很多人建议在 Active Directory 中查询某些内容。如果抛出异常,那么您就知道凭据无效 - 正如 this stackoverflow question 中所建议的那样。
不过有一些严重的drawbacks to this approach:
您不仅要验证域帐户,还要进行隐式授权检查。也就是说,您正在使用模拟令牌从 AD 中读取属性。如果其他有效帐户无权读取 AD 怎么办?默认情况下,所有用户都具有读取权限,但可以将域策略设置为禁用受限帐户(和/或组)的访问权限。
针对 AD 的绑定具有严重的开销,必须在客户端加载 AD 架构缓存(ADSI 缓存在 DirectoryServices 使用的 ADSI 提供程序中)。这既是网络,又是 AD 服务器,会消耗资源 - 并且对于验证用户帐户等简单操作而言过于昂贵。
您依赖于非异常情况的异常失败,并假设这意味着用户名和密码无效。其他问题(例如网络故障、AD 连接故障、内存分配错误等)随后被错误地解释为身份验证失败。
方法2.LogonUser Win32 API
Others 建议使用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 是 为所有用户启用,但有些 管理员可以禁用它 大家。
分发“作为操作系统的一部分”特权并不是你想做的事——正如微软在knowledge base article 中指出的那样:
...正在调用的进程 LogonUser 必须具有 SE_TCB_NAME 特权(在用户管理器中,这是 “作为运营的一部分 系统”对)。SE_TCB_NAME 特权非常强大并且 不应授予任何任意用户,以便他们可以 运行需要的应用程序 验证凭据。
此外,如果指定了空白密码,对LogonUser() 的调用将失败。
验证一组域凭据的正确方法是什么?
我碰巧从托管代码调用,但这是一个一般的 Windows 问题。可以假设客户已经安装了 .NET Framework 2.0。
【问题讨论】:
-
读者应该注意,从 Windows XP 开始,LogonUser 不再需要 SE_TCB_NAME(除非您正在登录 Passport 帐户)。
标签: c# windows security authentication