某些服务器应用程序需要客户端身份验证才能访问资源和服务 HTTP 请求。 从版本 2.0 开始,HTTP 服务器 API 对应用程序执行服务器端身份验证。 在 HTTP 服务器 API 版本 1.0 中,服务器应用程序必须实现自己的身份验证。 HTTP 服务器 API 执行的身份验证的一些优点包括:
- 应用程序可以在低特权下运行,从而降低安全风险。
- 身份验证在内核模式下执行,从而减少在身份验证期间从用户模式到内核模式的转换。
- 在内核模式下执行的身份验证允许服务器应用程序在不同的用户帐户上运行。 在版本 1.0 中,计算机上的所有应用程序都必须在同一用户帐户下运行,才能在服务主体名称(SPN)上进行身份验证。
- 如果在握手过程中回收工作进程,则 NTLM 身份验证握手不会重置。
为了利用版本 2.0 身份验证,应用程序启用 HTTP 服务器 API 应用于应用程序已注册的 URL 的身份验证方案。 可以在服务器会话或 URL 组中启用身份验证。 如果未在 URL 组上设置任何身份验证方案,URL 组将继承服务器会话启用的身份验证方案。 HTTP 服务器 API 支持以下方案:
- 谈判
- NTLM
- 消化
- 基本
服务器应用程序还可以实现 HTTP 服务器 API 不支持的身份验证方案。 HTTP 服务器 API 向应用程序发送请求,以获取不支持的身份验证方案,或应用程序未启用的方案。
启用身份验证
服务器应用程序使用 HttpSetServerSessionProperty 或 HttpSetUrlGroupProperty 函数在服务器会话或 URL 组中启用和配置身份验证,如下所示:
- 应用程序通过在 HttpSetServerSessionProperty 或 HttpSetUrlGroupProperty的 属性 参数中指定 HttpServerAuthenticationProperty 来启用身份验证。
- 应用程序在 pPropertyInformationHttpSetServerSessionProperty 或 HttpSetUrlGroupProperty的 HTTP_SERVER_AUTHENTICATION_INFO 结构中指定配置参数。 应用程序指定已启用的身份验证方案、是否禁用 NTLM 凭据缓存,并提供 HTTP_SERVER_AUTHENTICATION_INFO 结构中的“基本”和“摘要”参数。
身份验证过程
若要启动 HTTP 服务器身份验证,应用程序在第一个请求到达请求队列之前启用身份验证属性。 以下步骤是用于对请求进行身份验证的常见处理流。
应用程序启用身份验证。 请参阅前面的“启用身份验证”部分。
注意
客户端发送未经身份验证的请求。 HTTP 服务器 API 将请求传递给服务器应用程序,并允许它生成初始 401 质询。 HTTP 服务器 API 包括嵌入 HTTP_REQUEST 结构的 HTTP_REQUEST_AUTH_INFO 结构。 AuthStatus 成员指示 HttpAuthStatusNotAuthenticated
应用程序检查 AuthStatusHTTP_REQUEST_AUTH_INFO 结构的成员,以确定请求是否已进行身份验证。 如果未对请求进行身份验证,应用程序可以将请求作为匿名服务,或发送初始的 401 身份验证质询。
如果应用程序以匿名身份处理请求,它将处理请求并将最终响应发送到客户端应用程序,就好像身份验证未涉及一样。
如果应用程序需要身份验证,它会向客户端发送初始 401 质询,其中包含一个或多个 WWW-Authenticate 指示可用方案的标头。 当在响应中发送多个身份验证标头时,应用程序应使用 HTTP_MULTIPLE_KNOWN_HEADERS 结构来生成所需的标头集。
注意
客户端使用从服务器应用程序在初始 401 响应中指示的可用方案集中选择的方案的授权标头重新发送请求。
HTTP 服务器 API 检查授权请求授权标头,以确定方案是否已启用。 如果是,则 HTTP 服务器 API 执行身份验证并处理所有临时请求/401 响应交换,直到身份验证握手完成。
当 HTTP 服务器 API 完成身份验证尝试时,它会将请求发送到应用程序,并在请求返回的 HTTP_REQUEST_AUTH_INFO 结构中使用身份验证尝试的结果。 如果身份验证尝试失败,原因之一,HTTP 服务器 API 不会将请求传递给应用程序:
- 如果身份验证握手由于内部 HTTP 服务器 API 错误(例如内存分配失败)而失败,HTTP 服务器 API 将生成 503(服务不可用)响应并发送回客户端。
- 如果出现格式不正确的授权标头(例如没有方案名称的标头)或遇到客户端凭据格式不正确的 Base64 编码,则 HTTP 服务器 API 将生成 400(请求错误)响应并发送回客户端。
服务器应用程序检查 AuthStatusHTTP_REQUEST_AUTH_INFO 结构的成员,以确定身份验证是否成功。 身份验证失败时,HTTP 服务器 API 在 HTTP_REQUEST_AUTH_INFO 结构的 SecStatus 成员中包含从 AcceptSecurityContext 返回的错误。 如果身份验证尝试由于凭据错误而失败,则应用程序可以使用所需的 WWW-Authenticate 标头生成另一个 401 质询,或者可能决定以匿名方式为请求提供服务。
如果身份验证成功,应用程序将使用 HTTP_REQUEST_AUTH_INFO 结构中提供的令牌来模拟客户端和访问资源。 只要请求 ID 有效,返回到应用程序的访问令牌句柄就有效,这通常是在应用程序完成对请求的响应之前。 但是,令牌可能在此时间段内过期,应用程序可能需要向客户端发送另一个 401 质询。
应用程序发送最终的 200 OK 响应,并且必须关闭访问令牌的句柄。
注意
HTTP 服务器 API 会将相互身份验证数据追加到最终的 200 正常响应(如果在身份验证握手期间生成了一个身份验证数据)。
NTLM NULL 会话
请注意,最终安全上下文中指示的 NTLM NULL 会话不会被视为经过身份验证。 在这种情况下,请求会发送到应用程序,HTTP_REQUEST_AUTH_INFO 结构中出现 HttpAuthStatusFailure 错误,应用程序可以发送另一个 401 质询。
抢占式身份验证
根据 HTTP 协议,客户端为资源建立身份验证后,可以先发制人地发送相应的授权标头,并针对资源发出后续连续请求,而无需等待来自服务器的 401 质询。 如果授权标头中指示的方案仍由应用程序启用,并且由 HTTP 服务器 API 支持,则 HTTP 服务器会尝试身份验证,而不向应用程序发送请求。 当应用程序收到这种类型的经过身份验证的请求时,它可以选择放弃请求,并重新生成初始 401 质询或服务请求,以进行身份验证。
相互身份验证
在握手期间使用协商方案并解析为 Kerberos,并且客户端要求进行相互身份验证时,将生成相互身份验证数据。 相互身份验证数据由 HTTP 服务器 API 自动插入到服务器应用程序发送的最后 200 OK 响应中。 默认情况下,HTTP 服务器 API 不会将相互身份验证数据传递到服务器应用程序,因为它会自动处理发送数据。 但是,如果服务器应用程序在配置中的 HTTP_SERVER_AUTHENTICATION_INFO 结构中启用 ReceiveMutualAuth 标志,则相互身份验证数据将传递到嵌入了经过身份验证 HTTP_REQUEST的 HTTP_REQUEST_AUTH_INFO 结构中的应用程序。 在这种情况下,应用程序应发送具有最终 200 正常响应的相互身份验证数据。 如果多个站点由单个计算机提供服务,则计算机上的所有站点都使用域中本地计算机帐户的凭据进行相互身份验证。