一概述
身份验证是一个验证客户端身份的过程通常采用指定的第三方授权方式客户端可能是最终用户计算机应用程序或服务客户端的标识称为安全原则为了使用服务器应用程序进行验证客户端提供某种形式的凭据来允许服务器验证客户端的标识确认了客户端的标识后应用程序可以授予执行操作和访问资源的原则
如果应用程序使用 Active Directory 用户存储则应该使用集成 Windows 身份验证对 ASPNET 应用程序使用集成 Windows 身份验证时最好的方法是使用 ASPNET 的 Windows 身份验证提供程序附带的 Internet 信息服务 (IIS) 身份验证方法使用该方法将自动创建一个 windowsprincipal 对象(封装一个 windowsidentity 对象)来表示经过身份验证的用户您无需编写任何身份验证特定的代码
还支持使用 Windows 身份验证的自定义解决方案(避开了 IIS 身份验证)例如可以编写一个根据 Active Directory 检查用户凭据的自定义 ISAPI 筛选器使用该方法必须手动创建一个 windowsprincipal 对象
本文阐释在具有 IIS 的 ASPNET 中 Windows 身份验证的工作机制
二IIS 身份验证
如果 ASPNET 针对 Windows 身份验证进行配置则 ASPNET 依靠 IIS利用配置好的身份验证模式对其客户端进行身份验证IIS 通过检查特定应用程序的元数据库设置来确定其身份验证模式成功验证某个用户的身份后IIS 将代表经过身份验证的用户的 Windows 令牌传递给宿主 ASPNET 的 ASPNET 辅助进程 (wwpexe)如果应用程序使用在 IIS 中配置的虚拟目录来支持匿名访问该令牌代表匿名 Internet 用户帐户否则该令牌代表经过身份验证的用户
iis 支持以下身份验证模式
·匿名如果不需要对客户端进行身份验证(或者使用自定义身份验证机制如窗体身份验证)则可将 IIS 配置为允许匿名访问在该事件中IIS 创建一个 Windows 令牌来表示具有相同匿名(或客人)帐户的所有匿名用户默认的匿名帐户是 IUSR_MACHINENAME其中 MACHINENAME 是安装期间指定的计算机的 NetBIOS 名称
·基本基本身份验证要求用户以用户名和密码的形式提供凭据来证明他们的身份基本身份验证基于 Internet 标准 RFC 所有常用浏览器都支持它用户的凭据以未加密的 Base 编码格式从浏览器传送到 Web 服务器为了更好保护这些凭据只要在使用基本身份验证同时再使用安全套接字层 (SSL) 即可由于 Web 服务器包含未加密的用户凭据因此 ASPNET 应用程序可以模拟调用方并使用他们的凭据来访问网络资源
·集成的 Windows集成的 Windows 身份验证(以前称为 NTLM也称为 Windows NT 质询/应答身份验证Windows NT Challenge/Response)是使用 Kerberos v 身份验证还是 NTLM 身份验证取决于客户端和服务器的配置服务器与客户端协商确定要使用的协议如果满足以下条件则使用 Kerberos 身份验证
· Web 应用程序正在 NetworkService 帐户或自定义域帐户下运行如果应用程序在本地帐户(如 Windows Server 上的 ASPNET 帐户)上运行则使用 NTLM 身份验证
·域帐户的 Active Directory 中有一个服务主要名称 (SPN)该域帐户用于运行客户端进行身份验证所使用的服务
·客户端计算机和服务器计算机至少需要运行 Windows Server且处在相同的(即信任的)Windows 域中
注 默认情况下对于 Windows Server 操作系统启用集成 Windows 身份验证然而如果 Windows Server Service Pack (SP) 作为 Windows Server 操作系统整合安装的一部分进行安装则默认情况下禁用集成 Windows 身份验证如果使用 SP 升级 Windows Server 则集成 Windows 身份验证的设置与其 Windows Server 设置相同
应该使用集成 Windows 身份验证而不是基本身份验证因为前者避免了通过网络传输用户凭据由于 Kerberos v 身份验证支持相互身份验证因此用户还可以对正在连接的服务器进行身份验证
集成 Windows 身份验证最适合于 Intranet 环境其中的客户端计算机和 Web 服务器计算机都是相同(即信任的)域的一部分
三NTLM身份验证
ntlm 是用于 Windows NT 和 Windows Server 工作组环境的身份验证协议它还用在必须对 Windows NT 系统进行身份验证的混合 Windows Active Directory 域环境中当 Windows Server 转换为不存在下层 Windows NT 域控制器的本机模式时禁用 NTLM然后 Kerberos v 变成企业级的默认身份验证协议
ntlm 身份验证机制
图 显示 NTLM 协议
图 NTLM 质询/应答机制
下面概述质询/应答机制
· 用户请求访问用户尝试通过提供用户凭据登录到客户端登录前客户端计算机缓存密码的哈希值并放弃密码客户端向服务器发送一个请求该请求包括用户名以及纯文本格式的请求
· 服务器发送质询消息服务器生成一个称为质询的 字节随机数(即 NONCE)并将它发送到客户端
· 客户端发送应答消息客户端使用由用户的密码生成的一个密码哈希值来加密服务器发送的质询它以应答的形式将这个加密的质询发回到服务器
· 服务器将质询和应答发送到域控制器服务器将用户名原始质询以及应答从客户端计算机发送到域控制器
· 域控制器比较质询和应答以对用户进行身份验证域控制器获取该用户的密码哈希值然后使用该哈希值对原始质询进行加密接下来域控制器将加密的质询与客户端计算机的应答进行比较如果匹配域控制器则发送该用户已经过身份验证的服务器确认
· 服务器向客户端发送应答假定凭据有效服务器授予对所请求的服务或资源的客户端访问权
四Kerberos 身份验证
与 NTLM 身份验证相比Kerberos 身份验证具有以下优势
· 相互身份验证当客户端使用 Kerberos v 协议对特定服务器上的特定服务进行身份验证Kerberos 为客户端提供网络上恶意代码不会模拟该服务的保证
· 委托支持使用 Kerberos 身份验证对客户端进行身份验证的服务器可以模拟这些客户端并使用该客户端的安全上下文访问网络资源
· 性能Kerberos 身份验证提供优于 NTLM 身份验证的改进的性能
· 简化的信任管理具有多个域的网络不再需要一组复杂的显式点对点信任关系
· 互操作性Microsoft 实现的 Kerberos 协议基于向 Internet 工程任务组 (IETF) 推荐的标准跟蹤规范因此Windows 中协议的实现为与其他网络的互操作奠定了基础(其中 Kerberos 版本 用于身份验证)
kerberos 身份验证机制
图 显示 Kerberos 身份验证协议的简化视图
图 Kerberos 身份验证
当客户端对网络服务进行身份验证之后kerberos v 协议遵循以下步骤
· 客户端从 KDC 请求 TGT用户试图通过提供用户凭据登录到客户端客户端计算机上的 Kerberos 服务向密钥发行中心 (KDC) 发送一个 Kerberos 身份验证服务请求该请求包含用户名请求票证授予票证(ticketgranting ticketTGT)所获取的服务信息以及使用用户的长期密钥(即密码)加密的时间戳
注 在 Windows Server 或 Windows Server 操作系统上域控制器充当 KDC而 Active Directory 宿主安全帐户数据库
· 身份验证服务发送加密的 TGT 和会话密钥KDC 为来自 Active Directory 的用户获取长期密钥(即密码)然后解密随请求一起传送的时间戳如果该时间戳有效则用户是真正的用户KDC 身份验证服务创建一个登录会话密钥并使用用户的长期密钥对该副本进行加密然后该身份验证服务创建一个 TGT它包括用户信息和登录会话密钥最后该身份验证服务使用自己的密钥加密 TGT并将加密的会话密钥和加密的 TGT 传递给客户端
· 客户端从 TGT 请求服务器访问客户端使用其长期密钥(即密码)解密登录会话密钥并在本地缓存它此外客户端还将加密的 TGT 存储在它的缓存中访问网络服务时客户端向 KDC 票证授予服务(ticketgranting serviceTGS)发送一个包含信息的请求这些信息包括用户名使用用户登录会话密钥加密的验证者消息TGT以及用户想访问的服务(和服务器)名称
· TGS 发送加密的会话密钥和票证KDC 上的 TGS 使用自己的密钥解密 KDC 并提取登录会话密钥它使用该登录会话密钥解密验证者消息(通常是时间戳)如果验证者消息成功解密TGS 从 TGT 提取用户信息并使用用户信息创建一个用于访问该服务的服务会话密钥它使用该用户的登录会话密钥对该服务会话密钥的一个副本进行加密创建一个具有服务会话密钥和用户信息的服务票证然后使用该服务的长期密钥(密码)对该服务票证进行加密然后TGS 将加密的服务会话密钥和服务票证添加到客户端
· 客户端发送服务票证客户端访问服务时向服务器发送一个请求该请求包含验证者消息(时间戳)该消息使用服务会话密钥和服务票证进行加密
· 服务器发送加密的时间戳以进行客户端验证服务器解密服务票证并提取服务会话密钥通过使用服务会话密钥服务器解密验证者消息(时间戳)并计算它如果验证者通过测试则服务器使用服务会话密钥对验证者(时间戳)进行加密然后将验证者传回到客户端客户端解密时间戳如果该时间戳与原始时间戳相同则该服务是真正的客户端继续连接
服务的主要名称
kerberos v 身份验证协议之所以使用服务的主要名称 (SPN)原因如下
· 支持相互身份验证
· 允许一个客户端请求票证进而允许该客户端与特定服务通讯
例如如果某个客户端需要获得一个票证并对在侦听端口 运行的计算机 (myserver) 上的特定服务 (myservice) 进行身份验证则该客户端使用根据该信息构造的名称从 KDC 请求一个票证如下所示
MyService/MyServer在 Active Directory 中注册的 SPN 在该名称和运行所请求的服务的域帐户之间维护一个映射通过使用该机制恶意用户难以在网络上模拟服务恶意用户必须禁用实际服务并从该网络移除实际服务器然后恶意用户必须向网络中添加一台同名的新计算机并公开重复的服务由于客户端使用具有相互身份验证的 Kerberos v 协议因此该客户端将无法使用重复的服务除非它可以提供配置实际服务进行运行的域帐户的密码
五ASPNET身份验证
iis 向 ASPNET 传递代表经过身份验证的用户或匿名用户帐户的令牌该令牌在一个包含在 iprincipal 对象中的 iidentity 对象中维护iprincipal 对象进而附加到当前 Web 请求线程可以通过 属性访问 iprincipal 和 iidentity 对象这些对象和该属性由身份验证模块设置这些模块作为 HTTP 模块实现并作为 ASPNET 管道的一个标准部分进行调用如图 所示
图 ASPNET 管道
管道模型包含一个 httpapplication 对象多个 HTTP 模块对象以及一个 HTTP 处理程序对象及其相关的工厂对象httpruntime 对象用于处理序列的开头在整个请求生命周期中httpcontext 对象用于传递有关请求和响应的详细信息
有关 ASPNET 请求生命周期的详细信息请参阅ASPNET Life Cycle网址是 (enUSVS)aspx
身份验证模块
在计算机级别的 nfig 文件中定义一组 HTTP 模块其中包括大量身份验证模块如下所示
<httpModules>
<add name=WindowsAuthentication
type=SystemWebSecurityWindowsAuthenticationModule />
<add name=FormsAuthentication
type=SystemWebSecurityFormsAuthenticationModule />
<add name=PassportAuthentication
type=SystemWebSecurityPassportAuthenticationModule />
</httpModules>
只加载一个身份验证模块这取决于该配置文件的 authentication 元素中指定了哪种身份验证模式该身份验证模块创建一个 iprincipal 对象并将它存储在 属性中这是很关键的因为其他授权模块使用该 iprincipal 对象作出授权决定
当 IIS 中启用匿名访问且 authentication 元素的 mode 属性设置为 none 时有一个特殊模块将默认的匿名原则添加到 属性中因此在进行身份验证之后 绝不是一个空引用(在 Visual Basic 中为 nothing)
windowsauthenticationmodule
如果 nfig 文件包含以下元素则激活 windowsauthenticationmodule 类
<authentication mode=Windows />
WindowsAuthenticationModule 类负责创建 windowsprincipal 和 windowsidentity 对象来表示经过身份验证的用户并且负责将这些对象附加到当前 Web 请求
对于 Windows 身份验证遵循以下步骤
· WindowsAuthenticationModule 使用从 IIS 传递到 ASPNET 的 Windows 访问令牌创建一个 windowsprincipal 对象该令牌包装在 httpcontext 类的 workerrequest 属性中引发 authenticaterequest 事件时windowsauthenticationmodule 从 httpcontext 类检索该令牌并创建 windowsprincipal 对象 用该 windowsprincipal 对象进行设置它表示所有经过身份验证的模块和 ASPNET 页的经过身份验证的用户的安全上下文
· WindowsAuthenticationModule 类使用 P/Invoke 调用 Win 函数并获得该用户所属的 Windows 组的列表这些组用于填充 windowsprincipal 角色列表
· WindowsAuthenticationModule 类将 windowsprincipal 对象存储在 属性中随后授权模块用它对经过身份验证的用户授权
注defaultauthenticationmodule 类(也是 ASPNET 管道的一部分)将 threadcurrentprincipal 属性设置为与 属性相同的值它在处理 authenticaterequest 事件之后进行此操作
授权模块
WindowsAuthenticationModule 类完成其处理之后如果未拒绝请求则调用授权模块授权模块也在计算机级别的 nfig 文件中的 httpmodules 元素中定义如下所示
<httpModules>
<add name=UrlAuthorization
type=SystemWebSecurityUrlAuthorizationModule />
<add name=FileAuthorization
type=SystemWebSecurityFileAuthorizationModule />
<add name=AnonymousIdentification
type=SystemWebSecurityAnonymousIdentificationModule />
</httpModules>
urlauthorizationmodule
调用 urlauthorizationmodule 类时它在计算机级别或应用程序特定的 nfig 文件中查找 authorization 元素如果存在该元素则 urlauthorizationmodule 类从 属性检索 iprincipal 对象然后使用指定的动词(GETPOST 等)来确定是否授权该用户访问请求的资源
fileauthorizationmodule
接下来调用 fileauthorizationmodule 类它检查 属性中的 iidentity 对象是否是 windowsidentity 类的一个实例如果 iidentity 对象不是 windowsidentity 类的一个实例则 fileauthorizationmodule 类停止处理
如果存在 windowsidentity 类的一个实例则 fileauthorizationmodule 类调用 accesscheck Win 函数(通过 P/Invoke)来确定是否授权经过身份验证的客户端访问请求的文件如果该文件的安全描述符的随机访问控制列表 (DACL) 中至少包含一个 read 访问控制项 (ACE)则允许该请求继续否则fileauthorizationmodule 类调用 方法并将状态码 返回到客户端
六安全上下文
net Framework 使用以下两个接口封装 Windows 令牌和登录会话
· SystemSecurityPrincipalIPrincipal
· SystemSecurityPrincipalIIdentity(它公开为 iprincipal 接口中的一个属性)
在 ASPNET 中用 windowsprincipal 和 windowsidentity 类表示使用 Windows 身份验证进行身份验证的用户的安全上下文使用 Windows 身份验证的 ASPNET 应用程序可以通过 属性访问 windowsprincipal 类
要检索启动当前请求的 Windows 经过身份验证的用户的安全上下文使用以下代码
using SystemSecurityPrincipal;
// Obtain the authenticated users Identity
WindowsPrincipal winPrincipal = (WindowsPrincipal)HttpContextCurrentUser;
windowsidentitygetcurrent
WindowsIdentityGetCurrent 方法可用于获得当前运行的 Win 线程的安全上下文的标识如果不使用模拟线程继承 IIS (默认情况下的 NetworkService 帐户)上进程的安全上下文
该安全上下文在访问本地资源时使用通过使用经过身份验证的初始用户的安全上下文或使用固定标识您可以使用模拟重写该安全上下文
要检索运行应用程序的安全上下文使用以下代码
using SystemSecurityPrincipal;
// Obtain the authenticated users identity
WindowsIdentity winId = WindowsIdentityGetCurrent();
WindowsPrincipal winPrincipal = new WindowsPrincipal(winId);
threadcurrentprincipal
应用程序中的每个线程公开一个 currentprincipal 对象该对象保存经过身份验证的初始用户的安全上下文该安全上下文可用于基于角色的授权
要检索线程的当前原则使用以下代码
using SystemSecurityPrincipal;
// Obtain the authenticated users identity
WindowsPrincipal winPrincipal = (WindowsPrincipal) ThreadCurrentPrincipal();
表 显示从各种标识属性获得的结果标识当您的应用程序使用 Windows 身份验证且 IIS 配置为使用集成 Windows 身份验证时可以从 ASPNET 应用程序使用这些标识属性
表 线程公开的 CurrentPrincipal Objectnfig 设置变量位置结果标识
<identity impersonate=true/>
<authentication mode=Windows />
HttpContext
WindowsIdentity
线程
Domain\UserName
Domain\UserName
Domain\UserName
<identity impersonate=false/>
<authentication mode=Windows />
HttpContext
WindowsIdentity
线程
Domain\UserName
NT AUTHORITY\NETWORK SERVICE
Domain\UserName
<identity impersonate=true/>
<authentication mode=Forms />
HttpContext
WindowsIdentity
线程
用户提供的名称
Domain\UserName
用户提供的名称
<identity impersonate=false/>
<authentication mode=Forms />
HttpContext
WindowsIdentity
线程
用户提供的名称
NT AUTHORITY\NETWORK SERVICE
用户提供的名称
七模拟
应用程序可以使用模拟来执行操作使用经过身份验证的客户端或特定 Windows 帐户的安全上下文来访问资源
初始用户模拟
要模拟初始(经过身份验证的)用户请在 nfig 文件中使用以下配置
<authentication mode=Windows />
<identity impersonate=true />
使用该配置 始终模拟经过身份验证的用户且所有资源访问均使用经过身份验证的用户的安全上下文执行如果您的应用程序的虚拟目录上启用了匿名访问则模拟 IUSR_MACHINENAME 帐户
要暂时模拟经过身份验证的调用方将 identity 元素的 impersonate 属性设置为 false然后使用以下代码
using SystemSecurityPrincipal;// Obtain the authenticated users identityWindowsIdentity winId = (WindowsIdentity)HttpContextCurrentUserIdentity;WindowsImpersonationContext ctx = null;try{ // Start impersonating ctx = winIdImpersonate(); // Now impersonating // Access resources using the identity of the authenticated user}// Prevent exceptions from propagatingcatch{}finally{ // Revert impersonation if (ctx != null) ctxUndo();}// Back to running under the default ASPNET process identity
这段代码模拟经过身份验证的初始用户在 对象中维护初始用户的标识和 Windows 令牌
固定标识模拟
如果需要在应用程序的整个生命周期中模拟相同的标识可以在 nfig 文件中的 identity 元素上指定凭据以下示例显示如何模拟名为TestUser的 Windows 帐户
如果使用该方法应该对这些凭据进行加密使用 ASPNET 您可以使用 ASPNET IIS 注册工具 (Aspnet_regiisexe)使用 ASPNET 版您可以使用 Aspnet_setregexe 实用工具有关该实用工具的详细信息请参阅 ?url=/library/enus/cptools/html/cpgrfaspnetiisregistrationtoolaspnet_regiisexeasp
要在 ASPNET 应用程序中使用固定标识进行资源访问可使用 Windows Server 或 Windows Server 上的 identity 元素来配置凭据如果正在运行 Windows Server 其中的 IIS 配置为运行在辅助进程隔离模式下(默认情况)则可通过将 ASPNET 应用程序配置为在自定义应用程序池(在特定的域标识下运行)中运行来避免模拟然后可以使用指定的域标识访问资源而无需使用模拟
八委托
模拟只提供对本地资源的访问委托是一个扩展的模拟功能它允许您使用模拟令牌访问网络资源
如果应用程序使用 Kerberos v 身份验证对其用户进行身份验证则可使用 Kerberos 委托在应用程序的各层传递用户标识并访问网络资源如果应用程序不使用 Kerberos v 身份验证则可使用协议转换切换到 Kerberos然后使用委托传递该标识
windows Server 中的约束委托需要 Kerberos 身份验证如果您的应用程序无法使用 Kerberos 身份验证对其调用方进行身份验证您可以使用协议转换从可选的非 Windows 身份验证模式(如窗体或证书身份验证)切换到 Kerberos 身份验证然后可使用具有约束委托的 Kerberos 访问下游网络资源
约束的和未约束的委托
windows Server 上的 Kerberos 委托是未约束的Active Directory 中配置了委托的服务器可在使用模拟的用户安全上下文的同时访问任何网络资源或网络上的任何计算机这会带来潜在的安全威胁尤其是 Web 服务器遭受恶意用户攻击时
为了解决该安全问题windows Server 引入了约束的委托这使管理员能够在使用模拟的用户安全上下文时准确指定另一个服务器或域帐户可以访问的服务
配置委托
要使用 Kerberos 委托需要适当的 Active Directory 配置
要授予 Web 服务器委托客户端凭据的权限请按以下方式配置 Active Directory
· 如果在 NetworkService 帐户下运行应用程序Web 服务器计算机帐户必须在 Active Directory 中标记为受信任委托
· 如果在自定义域帐户下运行应用程序该用户帐户必须在 Active Directory 中标记为受信任委托
· 如果应用程序模拟一个用户帐户请确保应用程序模拟的用户帐户在 Active Directory 中未标记为敏感帐户不能被委托
有关协议转换和约束委托的详细信息请参阅 How To Use Protocol Transition and Constrained Delegation in ASPNET