如何针对域验证用户的缓存凭据?

Ian*_*oyd 5 windows security authentication windows-authentication

登录到Windows时,将缓存您的凭据.这允许您使用单点登录.如果您要浏览到另一台计算机,例如:

\\hydrogen
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

系统不会提示您输入凭据.

Windows将采取您的:

  • 当前用户名
  • (哈希)密码

并尝试自动验证您.有趣的是,如果您的工作站不在域上,这甚至可以工作.连接到服务器后,Windows将自动使用您的用户名和密码.如果你的:

  • 本地用户名/密码匹配a
  • 用户名/密码

你会自动进入.

美丽的照片:

在此输入图像描述

这称为单点登录.您登录Windows一次,并且在您使用网络上的其他内容时,您的缓存凭据将用于验证您.

浏览器也这样做

Chrome,Internet Explorer和Firefox也对此进行了修改.如果您需要登录到网站,并且服务器支持协商授权,服务器将向您发回一个指示,您应该尝试使用用户的Windows /域/ Kerberos凭据:

HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
Date: Thu, 09 Jul 2015 14:35:58 GMT
Content-Length: 0
Run Code Online (Sandbox Code Playgroud)

然后,Chrome会获取您的缓存凭据,并且(经过一些中级魔法)将它们转发到Web服务器:

GET http://hr.woodglue.com HTTP/1.1
Host: hr.woodglue.com
Authorization: Negotiate YIIFzwYGKwYBBQUCoIIFwzCCBb....
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Microsoft在旧文章中讨论了Internet Explorer中的这种机制:

使用协商协议进行基于HTTP的跨平台认证

在此输入图像描述

  • 客户端调用AcquireCredentialsHandle()InitializeSecurityContext()与SPN一起构建从TGS/KDC请求会话票证的安全上下文.

您验证域,而不是服务器

我要提到的最后一点是服务器,Web服务器,工作站,文件服务器,不验证服务器的凭据,它们针对域控制器进行验证.您有许多域服务器的模糊森林,其中一个处理您的请求.

换句话说,您不会针对以下内容验证凭据:

  • \\uranium (域上的woodglue.com域控制器)

您验证凭据:

  • woodglue.com域名

我们有一个重要的概念,有人可以:

  • 验证您的缓存凭据
  • 反对域名
  • 无需输入用户名或密码

我怎样才能做到这一点?

如何验证某人的缓存凭据?哪有:

  • 验证用户的缓存凭据
  • 反对域名
  • 无需用户不必输入用户名和密码(即使用Windows缓存的凭据)

重要的一点是,不知道(或关心):

  • 如果用户的计算机已加入域
  • 如果用户的计算机已加入工作组
  • 如果用户的机器加入了woodglue.com某个或其他某个域(例如superglue.com)
  • superglue.com域提供动力的服务器的名称

在此输入图像描述

我不知道怎么做.
我不知道涉及哪些API技术.

我知道有一个称为安全支持提供程序接口(SSPI)的API .这就是权力WWW-Authenticate: Negotiate(虽然我不知道它是否是来自非域名加入PC的SMB的权力).

Chromium的开源可能会让他们从他们的片段开始http_auth_sspi_win.cc.他们使用SSPI功能AcquireCredentialsHandle:

int AcquireDefaultCredentials(CredHandle* cred) 
{
   TimeStamp expiry;
   // Pass the username/password to get the credentials handle.
   // Note: Since the 5th argument is NULL, it uses the default
   // cached credentials for the logged in user, which can be used
   // for a single sign-on.
   SECURITY_STATUS status = library->AcquireCredentialsHandle(
         NULL,  // pszPrincipal
         const_cast<SEC_WCHAR*>(package),  // pszPackage
         SECPKG_CRED_OUTBOUND,  // fCredentialUse
         NULL,  // pvLogonID
         NULL,  // pAuthData
         NULL,  // pGetKeyFn (not used)
         NULL,  // pvGetKeyArgument (not used)
         cred,  // phCredential
         &expiry);  // ptsExpiry
}
Run Code Online (Sandbox Code Playgroud)

传递用户名/密码以获取凭据句柄.

注意:由于第5个参数为NULL,因此它使用登录用户的默认缓存凭据,该凭据可用于单点登录.

这个"出站"呼叫AcquireCredentialsHandle后跟呼叫InitializeSecurityContext.这个想法是InitializeSecurityContext生成一个代表客户端的不透明blob.

然后,您可以执行一组并行调用:

  • "入境"致电AcquireCredentialsHandle
  • 调用AcceptSecurityContext,传递之前返回的blobInitializeSecurityContext

为了重新宿主丹尼尔Doubrovkine的出色的图像:

在此输入图像描述

注意:在这种情况下,"客户端""服务器"用于指代生产者和消费者的上下文.在我的情况下,"客户端""服务器"在同一台机器上.

但是这一系列的"显示研究工作"分崩离析,因为我没有看到任何InitializeSecurityContext地方我可以指定woodglue.com作为要验证的域.

我知道InitializeSecurityContext联系kerberos服务器,并获得"票证" blob.然后将该票据blob传递给"服务器" AcceptSecurityContext.有时blob可以通过网络传递; 在我的情况下,它在同一台机器上的内存中传递.

但我不明白如何指定应该与域服务器船票.

并不是说SSPI对解决我的问题一点都有用.这只是"研究工作".

较早的研究工作

当然,在所有这些过程中,如果缓存的凭据在指定的域上无效,我将不得不提示用户输入用户名和密码.但用户名和密码是邪恶的,计算的祸根,我想避免它们.

我正在使用本机代码; 不是C#.