在 Cassini-dev 的 NTLM 身份验证类中的这段代码中,对 SECUR32.DLL(通过Interop)进行的调用是为了对 HTTP 请求Authorization
标头中的 base64 编码数据进行身份验证。这是有道理的,当AcceptSecurityContext()和QuerySecurityContextToken()都返回0
时,客户端已被授权。最后,安全上下文令牌SecurityIdentifier
从中提取了一个(_sid变量)。(关于常见安全 ID的一些信息)
int num = Interop.AcceptSecurityContext(ref _credentialsHandle, zero,
ref _inputBufferDesc, 20,
0, ref _securityContext, ref _outputBufferDesc,
ref _securityContextAttributes, ref _timestamp);
if (num == 0x90312)
{
securityContextAcquired = true;
_blob = Convert.ToBase64String(inArray, 0, (int) _outputBuffer.cbBuffer);
}
else
{
if (num != 0)
{
return false;
}
IntPtr phToken = IntPtr.Zero;
if (Interop.QuerySecurityContextToken(ref _securityContext, ref phToken) != 0)
{
return false;
}
try
{
using (WindowsIdentity identity = new WindowsIdentity(phToken))
{
_sid = identity.User;
}
}
finally
{
Interop.CloseHandle(phToken);
}
_completed = true;
在Request Class中,在TryNtlmAuthenticate()
使用 NtlmAuth 的方法中,在成功完成 NTLM 身份验证的 3 个步骤后,在返回最终403或完成请求之前,将进行最后一次检查:
if (_host.GetProcessSid() != auth.SID)
{
_connection.WriteErrorAndClose(0x193);
return false;
}
在这里,_host.GetProcessSid()是SecurityIndentifier
Cassini 进程(我)的所有者,而auth.SID是SecurityIdentifier
经过身份验证的用户(上面NtlmAuth类中的 _sid)。如果这 2 个 SID 不同,则返回 403 并停止身份验证,否则将请求提供给浏览器。
我的问题是:
- 为什么需要比较 2 个不同用户的 SecurityIndentifiers?当我尝试使用不是拥有 Cassini 进程的用户的用户/密码进行 NTLM 身份验证时,这将失败(返回 403)。
- 如果这确实是预期的行为,如果 Cassini 将作为 Windows 服务运行,则没有人能够登录,因为主机 SID 将是S-1-5-18(或者可能类似的东西,取决于操作系统版本)和没有人可以作为操作系统登录。这只是 Cassini 的 NTLM 身份验证实现的一部分,我没有正确使用 Cassini 吗?
- 如果这显然不是预期的行为,那么 SecurityIndentifiers 在这种情况下扮演什么角色?是否需要进行额外检查以确保主机 SID 需要属于某个类或组才能接受某个类/组的客户端 SID?处理主机/客户端 SID 时是否存在操作系统版本 (XP/Vista/7) 影响?
- 或者这里没有安全标识符的适用用途,因为它们没有被存储或传递,也没有被用来进一步识别用户/客户端?
更新:似乎有人在 cassinidev 论坛上提出了一个补丁,该补丁早在 2010 年就删除了此 SID 检查(补丁 #6604),但仍在评估中。