ASP.NET 2.0 中的 Windows 身份验证
一 概述
身份验证是一个验证客户端身份的过程 通常采用指定的第三方授权方式 客户端可能是最终用户 计算机 应用程序或服务 客户端的标识称为安全原则 为了使用服务器应用程序进行验证 客户端提供某种形式的凭据来允许服务器验证客户端的标识 确认了客户端的标识后 应用程序可以授予执行操作和访问资源的原则
如果应用程序使用 Active Directory 用户存储 则应该使用集成 Windows 身份验证 对 ASP NET 应用程序使用集成 Windows 身份验证时 最好的方法是使用 ASP NET 的 Windows 身份验证提供程序附带的 Internet 信息服务 (IIS) 身份验证方法 使用该方法 将自动创建一个 windowsprincipal 对象(封装一个 windowsidentity 对象)来表示经过身份验证的用户 您无需编写任何身份验证特定的代码
还支持使用 Windows 身份验证的自定义解决方案(避开了 IIS 身份验证) 例如 可以编写一个根据 Active Directory 检查用户凭据的自定义 ISAPI 筛选器 使用该方法 必须手动创建一个 windowsprincipal 对象
本文阐释在具有 IIS 的 ASP NET 中 Windows 身份验证的工作机制
二 IIS 身份验证
如果 ASP NET 针对 Windows 身份验证进行配置 则 ASP NET 依靠 IIS 利用配置好的身份验证模式对其客户端进行身份验证 IIS 通过检查特定应用程序的元数据库设置来确定其身份验证模式 成功验证某个用户的身份后 IIS 将代表经过身份验证的用户的 Windows 令牌传递给宿主 ASP NET 的 ASP NET 辅助进程 (w wp exe) 如果应用程序使用在 IIS 中配置的虚拟目录来支持匿名访问 该令牌代表匿名 Internet 用户帐户 否则 该令牌代表经过身份验证的用户
iis 支持以下身份验证模式
·匿名 如果不需要对客户端进行身份验证(或者使用自定义身份验证机制 如窗体身份验证) 则可将 IIS 配置为允许匿名访问 在该事件中 IIS 创建一个 Windows 令牌来表示具有相同匿名(或客人)帐户的所有匿名用户 默认的匿名帐户是 IUSR_MACHINENAME 其中 MACHINENAME 是安装期间指定的计算机的 NetBIOS 名称
·基本 基本身份验证要求用户以用户名和密码的形式提供凭据来证明他们的身份 基本身份验证基于 Internet 标准 RFC 所有常用浏览器都支持它 用户的凭据以未加密的 Base 编码格式从浏览器传送到 Web 服务器 为了更好保护这些凭据 只要在使用基本身份验证同时再使用安全套接字层 (SSL) 即可 由于 Web 服务器包含未加密的用户凭据 因此 ASP NET 应用程序可以模拟调用方并使用他们的凭据来访问网络资源
·集成的 Windows 集成的 Windows 身份验证(以前称为 NTLM 也称为 Windows NT 质询/应答身份验证 Windows NT Challenge/Response)是使用 Kerberos v 身份验证还是 NTLM 身份验证 取决于客户端和服务器的配置 服务器与客户端协商确定要使用的协议 如果满足以下条件 则使用 Kerberos 身份验证
· Web 应用程序正在 NeorkService 帐户或自定义域帐户下运行 如果应用程序在本地帐户(如 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 身份验证服务请求 该请求包含用户名 请求票证授予票证(ticket granting ticket TGT)所获取的服务信息 以及使用用户的长期密钥(即密码)加密的时间戳
注 在 Windows Server 或 Windows Server 操作系统上 域控制器充当 KDC 而 Active Directory 宿主安全帐户数据库
· 身份验证服务发送加密的 TGT 和会话密钥 KDC 为来自 Active Directory 的用户获取长期密钥(即密码) 然后解密随请求一起传送的时间戳 如果该时间戳有效 则用户是真正的用户 KDC 身份验证服务创建一个登录会话密钥 并使用用户的长期密钥对该副本进行加密 然后 该身份验证服务创建一个 TGT 它包括用户信息和登录会话密钥 最后 该身份验证服务使用自己的密钥加密 TGT 并将加密的会话密钥和加密的 TGT 传递给客户端
· 客户端从 TGT 请求服务器访问 客户端使用其长期密钥(即密码)解密登录会话密钥 并在本地缓存它 此外 客户端还将加密的 TGT 存储在它的缓存中 访问网络服务时 客户端向 KDC 票证授予服务(ticket granting service TGS)发送一个包含信息的请求 这些信息包括用户名 使用用户登录会话密钥加密的验证者消息 TGT 以及用户想访问的服务(和服务器)名称
· TGS 发送加密的会话密钥和票证 KDC 上的 TGS 使用自己的密钥解密 KDC 并提取登录会话密钥 它使用该登录会话密钥解密验证者消息(通常是时间戳) 如果验证者消息成功解密 TGS 从 TGT 提取用户信息 并使用用户信息创建一个用于访问该服务的服务会话密钥 它使用该用户的登录会话密钥对该服务会话密钥的一个副本进行加密 创建一个具有服务会话密钥和用户信息的服务票证 然后使用该服务的长期密钥(密码)对该服务票证进行加密 然后 TGS 将加密的服务会话密钥和服务票证添加到客户端
· 客户端发送服务票证 客户端访问服务时 向服务器发送一个请求 该请求包含验证者消息(时间戳) 该消息使用服务会话密钥和服务票证进行加密
· 服务器发送加密的时间戳以进行客户端验证 服务器解密服务票证并提取服务会话密钥 通过使用服务会话密钥 服务器解密验证者消息(时间戳)并计算它 如果验证者通过测试 则服务器使用服务会话密钥对验证者(时间戳)进行加密 然后将验证者传回到客户端 客户端解密时间戳 如果该时间戳与原始时间戳相同 则该服务是真正的 客户端继续连接
服务的主要名称
kerberos v 身份验证协议之所以使用服务的主要名称 (SPN) 原因如下
· 支持相互身份验证
· 允许一个客户端请求票证 进而允许该客户端与特定服务通讯
例如 如果某个客户端需要获得一个票证 并对在侦听端口 运行的计算机 (myserver) 上的特定服务 (myservice) 进行身份验证 则该客户端使用根据该信息构造的名称从 KDC 请求一个票证 如下所示
MyService/MyServer 在 Active Directory 中注册的 SPN 在该名称和运行所请求的服务的域帐户之间维护一个映射 通过使用该机制 恶意用户难以在网络上模拟服务 恶意用户必须禁用实际服务并从该网络移除实际服务器 然后 恶意用户必须向网络中添加一台同名的新计算机并公开重复的服务 由于客户端使用具有相互身份验证的 Kerberos v 协议 因此该客户端将无法使用重复的服务 除非它可以提供配置实际服务进行运行的域帐户的密码
五 ASP NET身份验证
iis 向 ASP NET 传递代表经过身份验证的用户或匿名用户帐户的令牌 该令牌在一个包含在 iprincipal 对象中的 iidentity 对象中维护 iprincipal 对象进而附加到当前 Web 请求线程 可以通过 属性访问 iprincipal 和 iidentity 对象 这些对象和该属性由身份验证模块设置 这些模块作为 HTTP 模块实现并作为 ASP NET 管道的一个标准部分进行调用 如图 所示
图 ASP NET 管道
管道模型包含一个 application 对象 多个 HTTP 模块对象 以及一个 HTTP 处理程序对象及其相关的工厂对象 runtime 对象用于处理序列的开头 在整个请求生命周期中 context 对象用于传递有关请求和响应的详细信息
有关 ASP NET 请求生命周期的详细信息 请参阅 ASP NET Life Cycle 网址是 (en US VS ) aspx
身份验证模块
在计算机级别的 nfig 文件中定义一组 HTTP 模块 其中包括大量身份验证模块 如下所示
<Modules> <add name= WindowsAuthentication type= System Web Security WindowsAuthenticationModule /> <add name= FormsAuthentication type= System Web Security FormsAuthenticationModule /> <add name= PassportAuthentication type= System Web Security PassportAuthenticationModule /></Modules>
只加载一个身份验证模块 这取决于该配置文件的 authentication 元素中指定了哪种身份验证模式 该身份验证模块创建一个 iprincipal 对象并将它存储在 属性中 这是很关键的 因为其他授权模块使用该 iprincipal 对象作出授权决定
当 IIS 中启用匿名访问且 authentication 元素的 mode 属性设置为 none 时 有一个特殊模块将默认的匿名原则添加到 属性中 因此 在进行身份验证之后 绝不是一个空引用(在 Visual Basic 中为 nothing)
windowsauthenticationmodule
如果 nfig 文件包含以下元素 则激活 windowsauthenticationmodule 类
<authentication mode= Windows /> WindowsAuthenticationModule 类负责创建 windowsprincipal 和 windowsidentity 对象来表示经过身份验证的用户 并且负责将这些对象附加到当前 Web 请求
对于 Windows 身份验证 遵循以下步骤
· WindowsAuthenticationModule 使用从 IIS 传递到 ASP NET 的 Windows 访问令牌创建一个 windowsprincipal 对象 该令牌包装在 context 类的 workerrequest 属性中 引发 authenticaterequest 事件时 windowsauthenticationmodule 从 context 类检索该令牌并创建 windowsprincipal 对象 用该 windowsprincipal 对象进行设置 它表示所有经过身份验证的模块和 ASP NET 页的经过身份验证的用户的安全上下文
· WindowsAuthenticationModule 类使用 P/Invoke 调用 Win 函数并获得该用户所属的 Windows 组的列表 这些组用于填充 windowsprincipal 角色列表
· WindowsAuthenticationModule 类将 windowsprincipal 对象存储在 属性中 随后 授权模块用它对经过身份验证的用户授权
注 defaultauthenticationmodule 类(也是 ASP NET 管道的一部分)将 thread currentprincipal 属性设置为与 属性相同的值 它在处理 authenticaterequest 事件之后进行此操作
授权模块
WindowsAuthenticationModule 类完成其处理之后 如果未拒绝请求 则调用授权模块 授权模块也在计算机级别的 nfig 文件中的 modules 元素中定义 如下所示
<Modules> <add name= UrlAuthorization type= System Web Security UrlAuthorizationModule /> <add name= FileAuthorization type= System Web Security FileAuthorizationModule /> <add name= AnonymousIdentification type= System Web Security AnonymousIdentificationModule /></Modules> urlauthorizationmodule
调用 urlauthorizationmodule 类时 它在计算机级别或应用程序特定的 nfig 文件中查找 authorization 元素 如果存在该元素 则 urlauthorizationmodule 类从 属性检索 iprincipal 对象 然后使用指定的动词(GET POST 等)来确定是否授权该用户访问请求的资源
fileauthorizationmodule
接下来 调用 fileauthorizationmodule 类 它检查 属性中的 iidentity 对象是否是 windowsidentity 类的一个实例 如果 iidentity 对象不是 windowsidentity 类的一个实例 则 fileauthorizationmodule 类停止处理
如果存在 windowsidentity 类的一个实例 则 fileauthorizationmodule 类调用 accesscheck Win 函数(通过 P/Invoke)来确定是否授权经过身份验证的客户端访问请求的文件 如果该文件的安全描述符的随机访问控制列表 (DACL) 中至少包含一个 read 访问控制项 (ACE) 则允许该请求继续 否则 fileauthorizationmodule 类调用 方法并将状态码 返回到客户端
六 安全上下文
net Framework 使用以下两个接口封装 Windows 令牌和登录会话
· System Security Principal IPrincipal
· System Security Principal IIdentity(它公开为 iprincipal 接口中的一个属性 )
在 ASP NET 中 用 windowsprincipal 和 windowsidentity 类表示使用 Windows 身份验证进行身份验证的用户的安全上下文 使用 Windows 身份验证的 ASP NET 应用程序可以通过 属性访问 windowsprincipal 类
要检索启动当前请求的 Windows 经过身份验证的用户的安全上下文 使用以下代码
using System Security Principal; // Obtain the authenticated user s IdentityWindowsPrincipal winPrincipal = (WindowsPrincipal)HttpContext Current User;
windowsidentity getcurrent
WindowsIdentity GetCurrent 方法可用于获得当前运行的 Win 线程的安全上下文的标识 如果不使用模拟 线程继承 IIS (默认情况下的 NeorkService 帐户)上进程的安全上下文
该安全上下文在访问本地资源时使用 通过使用经过身份验证的初始用户的安全上下文或使用固定标识 您可以使用模拟重写该安全上下文
要检索运行应用程序的安全上下文 使用以下代码
using System Security Principal; // Obtain the authenticated user s identity WindowsIdentity winId = WindowsIdentity GetCurrent();WindowsPrincipal winPrincipal = new WindowsPrincipal(winId); thread currentprincipal
应用程序中的每个线程公开一个 currentprincipal 对象 该对象保存经过身份验证的初始用户的安全上下文 该安全上下文可用于基于角色的授权
要检索线程的当前原则 使用以下代码
using System Security Principal; // Obtain the authenticated user s identityWindowsPrincipal winPrincipal = (WindowsPrincipal) Thread CurrentPrincipal(); 表 显示从各种标识属性获得的结果标识 当您的应用程序使用 Windows 身份验证且 IIS 配置为使用集成 Windows 身份验证时 可以从 ASP NET 应用程序使用这些标识属性
表 线程公开的 CurrentPrincipal Object nfig 设置 变量位置 结果标识
<identity impersonate= true /><authentication mode= Windows />
HttpContextWindowsIdentity线程
Domain\UserNameDomain\UserNameDomain\UserName
<identity impersonate= false /><authentication mode= Windows />
HttpContextWindowsIdentity线程
Domain\UserNameNT AUTHORITY\NEORK SERVICEDomain\UserName
<identity impersonate= true /><authentication mode= Forms />
HttpContextWindowsIdentity线程
用户提供的名称Domain\UserName用户提供的名称
<identity impersonate= false /><authentication mode= Forms />
HttpContextWindowsIdentity线程
用户提供的名称NT AUTHORITY\NEORK SERVICE用户提供的名称
七 模拟
应用程序可以使用模拟来执行操作 使用经过身份验证的客户端或特定 Windows 帐户的安全上下文来访问资源
初始用户模拟
要模拟初始(经过身份验证的)用户 请在 nfig 文件中使用以下配置
<authentication mode= Windows /><identity impersonate= true /> 使用该配置 始终模拟经过身份验证的用户 且所有资源访问均使用经过身份验证的用户的安全上下文执行 如果您的应用程序的虚拟目录上启用了匿名访问 则模拟 IUSR_MACHINENAME 帐户
要暂时模拟经过身份验证的调用方 将 identity 元素的 impersonate 属性设置为 false 然后使用以下代码
using System Security Principal; // Obtain the authenticated user s identity WindowsIdentity winId = (WindowsIdentity)HttpContext Current User Identity; WindowsImpersonationContext ctx = null; try { // Start impersonating ctx = winId Impersonate(); // Now impersonating // Access resources using the identity of the authenticated user } // Prevent exceptions from propagating catch { } finally { // Revert impersonation if (ctx != null) ctx Undo(); } // Back to running under the default ASP NET process identity
这段代码模拟经过身份验证的初始用户 在 对象中维护初始用户的标识和 Windows 令牌
固定标识模拟
如果需要在应用程序的整个生命周期中模拟相同的标识 可以在 nfig 文件中的 identity 元素上指定凭据 以下示例显示如何模拟名为 TestUser 的 Windows 帐户
如果使用该方法 应该对这些凭据进行加密 使用 ASP NET 您可以使用 ASP NET IIS 注册工具 (Aspnet_regiis exe) 使用 ASP NET 版 您可以使用 Aspnet_setreg exe 实用工具 有关该实用工具的详细信息 请参阅 ?url=/library/en us/cptools//cpgrfaspnetiisregistrationtoolaspnet_regiisexe asp
要在 ASP NET 应用程序中使用固定标识进行资源访问 可使用 Windows Server 或 Windows Server 上的 identity 元素来配置凭据 如果正在运行 Windows Server 其中的 IIS 配置为运行在辅助进程隔离模式下(默认情况) 则可通过将 ASP NET 应用程序配置为在自定义应用程序池(在特定的域标识下运行)中运行来避免模拟 然后 可以使用指定的域标识访问资源而无需使用模拟
八 委托
模拟只提供对本地资源的访问 委托是一个扩展的模拟功能 它允许您使用模拟令牌访问网络资源
如果应用程序使用 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
· 如果在 NeorkService 帐户下运行应用程序 Web 服务器计算机帐户必须在 Active Directory 中标记为受信任委托
· 如果在自定义域帐户下运行应用程序 该用户帐户必须在 Active Directory 中标记为受信任委托
· 如果应用程序模拟一个用户帐户 请确保应用程序模拟的用户帐户在 Active Directory 中未标记为 敏感帐户 不能被委托
有关协议转换和约束委托的详细信息 请参阅 How To Use Protocol Transition and Constrained Delegation in ASP NET
lishixinzhi/Article/program/net/201311/13414