如何执行Windows身份validation?

SQL Server,文件和打印机共享,Exchange以及许多其他应用程序都可以根据用户的Windows标识对用户进行身份validation

他们如何做到这一点? 特别是,我该怎么做?

作为一个具体的例子,在下面的方法中完成原生Windows代码:

Boolean IsCurrentUserValidForDomain(String domainName) { //TODO: Ask Stackoverflow to fill in the code here } 

我可以让我们开始:

 Boolean IsCurrentUserValidForDomain(String domainName) { //Get the security token associated with the thread TOKEN userToken; // Get the calling thread's access token. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, out userToken) { if (GetLastError != ERROR_NO_TOKEN) throw new Exception("Could not get current thread security token"); // Retry against process token since no thread token exists. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out userToken) throw new Exception("Could not get current process security token"); } //We now have the security token of the running user (userToken) //From this, we can get the SID of the user PSID sidUser = null; DWORD cbBuf = 0; Boolean bsuccess = GetTokenInformation(hToken, TokenUser, null, 0, ref cbBuf); PTOKEN_USER ptiUser = null; while ((!bSuccess) && (GetLastError() = ERROR_INSUFFICIENT_BUFFER)) { ReallocMem(ref ptiUser, cbBuf); bSuccess = GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, ref cbBuf); } sidUser = ptiUser.User.Sid; //Now that we have the user's SID, we can get the SID of their domain PSID sidDomain = null; GetWindowsAccountDomainSid(sidUser, null, ref cbBuff); ReallocMem(sidDomain, cbBuff); GetWindowsAccountDomainSid(sidUser, sidDomain, ref cbBuff); //We now have //TOKEN userToken: security token of the running user //PSID sidUser (S-1-5-21-2154378322-3929449213-1104335884-1006) //PSID sidDomain (S-1-5-21-2154378322-3929449213-1104335884) //TODO: ask stackoverflow if anything i've computed so far can help //answer the question //TODO: Ask Stackoverflow to fill in the code here } 

注意:从这里开始的一切都是“显示研究工作” 。 你现在可以停止阅读了。 我只有它logging我自己的研究工作(其中一些在其他情况下可能非常有用)。 我也想避免一些更常见和不安全的方法(这是我陷入陷阱的一个陷阱)。 如果我能帮助别人避免同样的陷阱 – 一切都会好起来。

背景

当用户连接到SQL Server时,他们可以select使用集成身份validation

集成安全性使用在操作系统线程上build立的当前Windows标识来访问SQL Server数据库

和更多从SQL Server:

当用户通过Windows用户帐户连接时,SQL Server使用操作系统中的Windows主体令牌validation帐户名称和密码。 这意味着用户身份被Windows确认。 SQL Server不会要求input密码,也不会执行身份validation。

结果:我可以login到SQL Server而不必input用户名和密码

如果我连接到远程networking共享,我自己的用户凭据用于validation我是远程服务器上的用户。 我可以浏览到远程机器和连接隐式使用我login的用户帐户来validation访问。

结果 :我可以连接到networking共享,而无需input用户名和密码。

SQL Server如何validation我作为用户?
文件和打印机共享如何validation我作为用户?

比方说,我正在写我自己的数据库引擎,我想支持“Windows身份validation”,我会怎么做呢?

比方说,我的SQL数据库引擎运行在一个非域joinPC,本地用户帐户。 我可以得到关于他们的各种信息

本地用户

  • GetUsernameginger
  • GetUsernameEx(NameSamCompatible)HYDROGEN\Ginger (氢是机器的名字)
  • GetTokenInformation(TokenUser) :UserSID = S-1-5-21-2154378322-3929449213-1104335884-1006
  • 执行LookupAccountSid
    • 用户名: Ginger
    • 域名: HYDROGEN
  • GetWindowsAccountDomainSidS-1-5-21-2154378322-3929449213-1104335884

比方说,我的SQL数据库引擎运行在一个join了个人电脑的域名,并且有一个域名用户帐号(为了让用户感兴趣,用户来自不同于机器join域的域名)。 我可以得到有关用户的各种信息:

  • GetUsernameforest
  • GetUsernameEx(NameSamCompatible)CONTOSO\forest (contoso是遗留的SAM兼容的域名的NetBIOS,实际的域名是contoso.com)
  • GetTokenInformation(TokenUser) :UserSID = S-1-5-21-1708537768-854245398-2146844275-3110
  • 执行LookupAccountSid
    • 用户名: forest
    • 域名: CONTOSO
  • GetWindowsAccountDomainSidS-1-5-21-1708537768-854245398-2146844275

是否有足够的信息在这里正确实现Windows身份validation

SQL Server如何做到这一点? Explorer如何做到这一点? Internet Explorer如何与IIS一起使用?

是不是有一些stream行语,像我要包括的票务授权票(Ticket-Granting-Ticket) ?

糟糕的想法

我有一些不好的,不安全的想法。 我想,为什么不只是从GetUsernameEx返回名称

 CONTOSO\forest 

并将其分为两部分:

 Username: forest Domain: CONTOSO 

这样我知道用户确实是来自CONTOSO域的用户 。 我知道它确实是contoso \ forest,因为Windows在login时validation了他们的凭据。

除了没有。 因为用户在其独立的,非域名join的笔记本上可以将其工作组的名称从HYDROGEN更改为CONTOSO 。 现在当我阅读他们的用户名:

 CONTOSO\forest 

我会相信他们是:

CONTOSO域的森林

实际上他们是:

独立机器的森林

好的,请使用SID

由于我不能相信由各种Windowsfunction返回的“域名” ,那么我可以使用用户的SID

域用户contoso \ forest: S-1-5-21-1708537768-854245398-2146844275-3110

独立PC上的用户无法伪造,对吧? 对? 🙁

是的他们可以:

本地用户氢\姜: S-1-5-21-1708537768-854245398-2146844275-3110

你看到我要去哪里? 我试图发明一种方法来执行身份validation – 并失败。 同时Windows和SQL Server团队二十年前已经解决了这个问题。 Dave Cutler于1994年devise了这个系统,并且确切地知道我应该做什么。

我只是不知道那是什么

用户SID不用于身份validation

在研究这个时候,我发现了一些有趣的概念。 比如一个域的SID是第一台机器的机器 SID成为域控制器。 我还发现该域中的用户是域SID的后缀:

机器SID和域SID

 | Machine SID for computer DEMOSYSTEM | S-1-5-21-3419697060-3810377854-678604692 | | DEMOSYSTEM\Administrator | S-1-5-21-3419697060-3810377854-678604692-500 | | DEMOSYSTEM\Guest | S-1-5-21-3419697060-3810377854-678604692-501 | | DEMOSYSTEM\CustomAccount1 | S-1-5-21-3419697060-3810377854-678604692-1000 | | DEMOSYSTEM\CustomAccount2 | S-1-5-21-3419697060-3810377854-678604692-1001 | 

在工作组系统上,本地帐户和组都在那里。 使用本地帐户对远程系统进行身份validation需要远程系统已知的用户名和密码,并且不使用SID。 如果远程系统使用的用户名和密码与呼叫者使用的相同,则本地帐户发生类似单点login的唯一方法是。 SID不传输,不用于远程authentication。

这是重要的一点,你必须认识到重复的SID是完全有效的 。 SID 在使用权限内必须是唯一 。 因此,虽然DEMOSYSTEM只能有一个SID为S-1-5-21-3419697060-3810377854-678604692-1000的本地帐户,但如果另一台计算机使用相同的SID来引用本地帐户,则无关紧要。

这是有道理的,并且强化了authenticationauthentication用户的凭证 ,而不是他们的SID。

这就是为什么我的另一个想法很糟糕

SQL Server通过在syslogins表中的SID存储Windowslogin:

 sid name isntuser ---------------------------------------------------------- -------------- --------- 0x010500000000000515000000A837D66516C0EA32733EF67F260C0000 CONTOSO\forest 1 

我的SQL数据库引擎无法读取当前用户的SID,并检查它是否存在于我的syslogins表中,因为可能有多个用户使用相同的sid通过TCP端口1434连接到我的数据库引擎。

Windows在某处存储凭据

我正在阅读关于NTML和Kerberos的“通过哈希”攻击。 有一个有趣的片段 :

Windows将散列的密码caching在内存中,以实现Single Sign On或SSO,这是Windows企业环境的基本特性。

我只需要弄清楚如何说服Windows来告诉我用户是否真的是domain\BillG

Chrome和Windows资源pipe理器中的Windows身份validation

Chrome能够透明地将我的Windows credentails提供给请求他们的人。 如果我要求在服务器上,服务器将拒绝我访问(401),并指出我应该使用Negotiate身份validation:

 HTTP/1.1 401 Unauthorized WWW-Authenticate: Negotiate 

然后,我的客户执行一些魔术 ,并重新发出请求,这次我的身份附加:

 GET http://contoso.com/foo HTTP/1.1 Authorization: Negotiate YIIFzwYGKwYBBQUCoIIFwzCCBb+gMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHgYKKwYBBAGCNwICCqKCBYkEggWFYIIFgQYJKoZIhvcSAQICAQBuggVwMIIFbKADAgEFoQMCAQ6iBwMFACAAAACjggP4YYID9DCCA/CgAwIBBaEOGwxBVkFUT1BJQS5DT02iJTAjoAMCAQKhHDAaGwRIVFRQGxJ2YWRlci5hdmF0b3BpYS5jb22jggOwMIIDrKADAgEXoQMCATCiggOeBIIDmjMA0SnAUdqmbf8+UXZHsipRqPKt2yxqQaFia8hBF3TuQVDBgqGk8yL+CoDGnvkyGqpZK3UBsS/EuXP4Z+/0y49ZyDDQnDFqcJpF5ZY87t+u/kYQy+dr42GxEYQIjb096AQzDZio0dRWqbHleS5DlR7wCEaJ+a0CG6/vLEXL6tT20aj3avFibZc++5OKhynoxtyh10tJO3iwun2usJT+p1IfTD9yVDhfplMchLBgyp803+6IUwzm0zcwcqt7R1KnCv1i+baw3e/dhkIJz8cnoh1oNuivSXf4zOqlvp8FDlQMQEGqa9OA7LBmhg1rWDTOdyB4E9oZtVG8ipHyFYzDcyvIpWOMf9S68TTE78TgEhWjVq7g6BoH+O6IW14QIItxVk1GbSd2Ke9n9We0pbMjRxiZIMqyOvvFBgU5NlUUksdlG/yv0BTai7SILbVfNPsVwHeus//UfKQenX6YEnKUVi+XutY0kjLyp6l1L3Ce/ovkpDVmmYFebfdIT8Xbya9Zksa2nF8+7OL5S7I0tZaZUBL2Bzca9VJiGioRFvpgBXxKiChv71SukROreic+ylxHOfOWwXsEa0+ISHV6Uvhd44y3UA2VKtI3xoF8+3SZ184hIZ4fbahkfrBa1Zu5FqQ9M0rxAPgmsBZ2PwuMDWWLtraK7gJsAh+DxXGAaSTiPWaRhms59mfetBmzSnkzWBCr63G8rL71TiDgevoxhv0FP5s1JmWzWsnluJ95f9fphItuiDRI0C1358LMai9B1ZFWf9CRooeMAH4YUuL4SZ0r61/zQVnWFF1ngyt/ko/9UQ3mErLFeA/9Oq6BYfI/ExhVl9VVue0irM1vk09pIdUMS9MvQdW7YCg/C9LtOiJVpYw/aEVakn74l7TM71bIfjucDddDCBNuup41bWy5Nqkci8AHEMyoVyG9BxHmTm8NZ3FSujl+MeDAANKSt3a6P2k0C/W4Mley76ZoAGf6IYXf/9THQucvQGkasUkIN6PwIZIaxEdVt1BXiVXu1ADgt2/+0UB8rzYq+kt53R16rjev4Exvt7jpHIWUxjbDTxo2CvW0+Eh+mFyMj3CS2xQlhjrU2Q9ADQqA8wf8H88Dzp4PPWPxJnB4tC+Ecd9ZYlQwal00UX6aN47+dKPYDCp4piq6dvr2BhpzpsXxyR8QOZRKqAoXXLmb4Y1eGFWiUqH56J3Wju5h+cyzhMq+otpI4s77lfIecM41HccPrTKkggFZMIIBVaADAgEXooIBTASCAUigcKId1qR+UzSz8R00q+0o2M4+2dLnNW2vPU+uLeG9SqLJgJWsgBWUGtt6TRvPLF/GoHxP+sqST8fKJf0EHfycGfH/VJR6bnfpQYCWCgWRHjfdUpll51G/xKYqJYyy5xtNQvtKkzp+IB6CVKe1q3wopAY+uDsUk9XUvaIbUtHDEcWDATwi8BKGggVunw/idxKaZjaRmRko/Nsj5p38fiBk+OCN3yKDNSFCTDn+HUiCoCbDsv03zt2EO1eTJUPxXNhqJUjZMKYodgcsLMzNhSiyySH+kvgQZci3b8LGY1sCHMXopaL0Ysu4QgPD8UDD7dIBZ0ORmGf9srdZMgKjLIoEhXOmg+y5kqJpoPAwQaooHDizKQ8bmhFX2pOp7NjXoJ/wRvTB98seUNlDXDl5ySrt7P3Xf1Ybj7PpgMuqJykou2lKxirVhYYJ 

IE和Chrome都能够转身,做些事情可以用来certificate我是谁。 如何Windows身份validation没有logging,但有一些提示。 从MSDN:通过协商协议基于HTTP的跨平台validation第一部分 – networking基础设施 :

在这里输入图像说明

  1. 当login用户从Web服务器请求资源时,它将发送最初的HTTP GET动词。
  2. 运行SPNEGO令牌处理程序代码的Web服务器需要进行身份validation,并发出拒绝访问响应(WWW-Authenticate:Negotiate)响应。
  3. 客户端使用SPN调用AcquireCredentialsHandle()InitializeSecurityContext()来构build请求来自TGS / KDC的会话票证的安全上下文。
  4. TGS / KDC为客户端提供必要的Kerberos票证(假设客户端是授权的),并包装在SPNEGO令牌中。
  5. 客户端在授权:协商base64(令牌)标头中重新发送HTTP GET请求+协商SPNEGO令牌。
  6. Web服务器的SPNEGO令牌处理程序代码通过GSS API接受并处理令牌,对用户进行身份validation并用请求的URL进行响应。

在这里输入图像说明

所以客户端可以使用一些代码来生成一个certificate他们是谁的certificate。 这意味着在我的客户端有一些方法可以生成域用户是他们所说的域用户的certificate。

当然,我并不需要将encryption的,基于64位的SPNEGO blob中的Kerberos票据打包。 我只需要正确的API调用,以正确的顺序,知道我是谁我说我是。

经过一些澄清之后,在Windows和Unix上使用SSPI和GSS-API可以很容易地实现这一点。

  1. 在目标主机上注册服务的SPN

客户端视图:

  1. 在您的应用/客户端中使用C / C ++和SSPI / GSS-API。
  2. 获取当前用户的凭证句柄(出站/启动器)。 GetUsername...不是必需的。
  3. 为给定的机制创建一个SSPI / GSS上下文。 Kerberos或SPNEGO。

服务器视图:

  1. 在目标主机/服务器上使用C / C ++和SSPI / GSS-API。
  2. 获取SPN绑定到的机器/服务帐户的凭证句柄(入站/接受方)。 GetUsername...不是必需的。

客户端视图:

  1. 让上下文生成一个不透明的令牌并通过套接字发送给服务器

服务器视图:

  1. 接受该令牌并作出回应。 …在循环中重复,直到上下文已经建立。
  2. 查询已认证用户的上下文属性,例如michael-o@STACKOVERFLOW.COM
  3. 配置上下文和凭证句柄

客户端视图:

  1. 配置上下文和凭证句柄
  2. 在已认证的套接字上执行通信

安全建议:不要依赖stoneage NTLM,尽可能使用Kerberos。 也总是使用UPN。