为什么PrincipalContext:: validatecredals接受密码过期的凭据?



我们有一个用内部ActiveDirectory域验证用户凭据的应用程序。为此,它使用了。net框架中的PrincipalContext::ValidateCredentials方法。

在调查另一个问题时,我们发现该方法即使在密码过期时也返回true。这导致用户能够访问我们的一个互联网系统,尽管在某些情况下,密码过期了几个月,甚至几年。这看起来很奇怪,这是一个严重的安全漏洞,我们现在需要修复,我们已经意识到这一点。

我试着在网上查找这种行为,但到目前为止我什么也没找到。据我所知,如果帐户有任何问题,该方法实际上应该拒绝凭据。例如,当帐户被锁定时,它确实返回false。

我怀疑这是ValidateCredential方法本身的错误。它已经存在太久了。它使用起来相当简单,所以我认为我们没有搞砸。下面是我们的代码:

using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domainName))
{
bool valide = context.ValidateCredentials(userName, passWord);
// Remaining code omitted
}

那么,这里可能发生了什么?什么可能导致validatecredals接受过期的密码?

源代码显示它尝试了简单的SSL绑定和协商。由于某种原因,它可能是身份验证方法之一。我不知道为什么它会允许。

您可以在构造函数中为PrincipalContext指定不同的ContextOptions。例如(因为您说SSL按照您期望的方式执行):

using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domainNam 
, ContextOptions.SecureSocketLayer | ContextOptions.SimpleBind))
{
bool valide = context.ValidateCredentials(userName, passWord);
// Remaining code omitted
}

但是如果你必须改变你的代码,你可以考虑直接使用LdapConnection,因为异常会告诉你它失败的原因,正如我链接到的那个例子所描述的。

事实证明,需要深入研究。net框架源代码才能找出原因,validatecredals允许过期密码的原因是因为它尝试通过SSL和Negotiate进行简单绑定,但是当它进行简单绑定时,它激活了对快速并发绑定的支持,这显然只验证用户具有有效的启用帐户和密码。

以下是O'Reilly关于快速并发绑定的Active Directory Cookbook摘录:

并发绑定与简单绑定不同,它不会在身份验证过程中生成安全令牌或确定用户的组成员关系。它只确定身份验证用户是否具有有效的启用帐户和密码,这使得它比典型绑定快得多。并发绑定是作为会话选项实现的,该会话选项是在您建立到域控制器的连接之后,但在进行任何绑定尝试之前设置的。设置该选项后,对该连接进行的任何绑定尝试都将是并发绑定。

是的,我知道这本书很旧,但我认为这部分仍然相当有效。我所做的测试似乎证实了这一点,因为validatecredals将接受过期的密码,但不接受锁定的帐户。

那么,如何预防呢?其实很简单:

using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domainName))
{
bool valide = context.ValidateCredentials(userName, passWord, ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing);
// Remaining code omitted
}

技巧是指定连接选项,但在validatecredals方法中,而不是在PrincipalContext构造函数中,否则validatecredals会忽略这些选项,并尝试与有问题的行为进行快速绑定。

感谢Gabriel Luci为我指出了正确的方向。

最新更新