ASP.NET 1.1 版 Web 应用程序和 Windows 身份验证——一个案例研究






4.27/5 (26投票s)
本案例研究的目的是解释如何使用“集成 Windows 身份验证”来实现 ASP.NET Web 应用程序的应用程序安全。
1. 引言
应用程序安全在信息管理中起着重要作用。将正确的信息在正确的时间分发给正确的人是信息管理的基石。除了确保信息能够到达正确的人手中,还必须确保信息绝不会落入未经授权的人手中。这就是信息安全的作用。提供应用程序安全是确保信息安全的重要方面。应用程序安全的主要目的是保护应用程序和数据免遭未经授权的访问。
本案例研究的目的是解释如何使用“集成 Windows 身份验证”来实现 ASP.NET Web 应用程序的应用程序安全。
2. 如何保护 Web 应用程序
身份验证和授权是确保应用程序安全的两个因素。
2.1. 身份验证
身份验证是决定谁可以访问应用程序的过程。用户名和密码是最常见的身份验证机制。
2.2. 授权
授权是决定已通过身份验证的用户可以使用应用程序执行哪些操作的过程。应用程序可以为不同用户提供不同的访问功能。可以根据用户类型限制对各种功能的访问。这称为基于角色的授权。例如,“管理员”的访问权限将比“访客用户”多得多。
3. 什么是“集成 Windows 身份验证”?
在集成 Windows 身份验证中,应用程序会利用 Windows 用户的凭据。IIS 将客户端凭据提供给 ASP.NET。根据应用程序特定的安全体系结构,应用程序可以根据为应用程序配置的“访问权限信息”来验证这些凭据。只有在验证成功后,用户才能访问应用程序。
3.1. 单点登录
此技术允许用户使用相同的凭据访问多个应用程序。用户成功登录操作系统后,其他应用程序就可以从操作系统利用这些凭据。“单点登录”可以通过使用“集成 Windows 身份验证”在 ASP.NET 应用程序中实现。用户一旦登录到 Windows 操作系统,他/她就可以自由访问应用程序,就像不再需要登录一样(前提是用户已获得应用程序的访问权限)。但是,在应用程序启动时,它会 silently 检查用户凭据与为应用程序配置的“访问权限信息”。只有在凭据匹配时,用户才能访问应用程序。
4. “Windows 身份验证”适用于何处?
由于“Windows 身份验证”使用 Windows 用户的凭据,因此它只能用于内网应用程序。在内网应用程序中,管理员可以完全控制网络用户。应用程序可以设计成显示所有“Active Directory”用户,以便应用程序管理员配置应用程序已进行身份验证的用户。集成 Windows 身份验证最适合内网环境,在这种环境中,用户计算机和 Web 服务器计算机都在同一个域中,并且管理员可以确保每个用户都安装了 Microsoft Internet Explorer 2.0 或更高版本。
5. Windows 身份验证和授权方案
使用 WindowsAuthenticationModule 提供程序,只需最少的 ASP.NET 编码即可为 Web 应用程序提供安全性。提供程序模块会构造一个 WindowsIdentity
对象。默认实现会构造一个 WindowsPrincipal
对象并将其附加到应用程序上下文中。WindowsPrincipal
对象将标识映射到 Windows 组。使用 web.config 文件的 authorization
标记,可以限制用户/组访问各种应用程序文件夹。
也可以实现自定义 Windows 授权方案。为此,可以使用 WindowsAuthentication_OnAuthenticate
事件处理程序从 WindowsIdentity
对象创建 WindowsPrincipal
或 GenericPrincipal
对象。然后,可以使用其中一个新对象来实现自己的自定义身份验证方案。
6. “Windows 身份验证”如何工作——一个案例研究
这是一个案例研究,展示了如何在 ASP.NET 中实现 Windows 身份验证和基于角色的安全性。它从详细的问题定义开始,然后是解决方案架构。它还提供了解决方案实现的详细步骤。
6.1. 问题定义
这是一个为跨国公司 ABC 准备商业计划的 Web 应用程序。所有用户都注册在其内网域的 Active Directory 中,并需要从该内网访问该应用程序。该应用程序为用户提供以下功能:
- 准备主数据
- 创建商业计划
- 批准或拒绝计划
- 准备报告
主数据(MD)用户的访问权限应严格限制在“准备主数据功能”,而中央支持团队(CST)可以访问所有功能,但不能访问“批准或拒绝计划”。区域经理(AM)只能访问“批准或拒绝计划”和“准备报告”。根据此要求,我们需要为该应用程序实现基于角色、单点登录的安全性。
6.2. 解决方案架构
我们可以使用“Windows 身份验证”为该应用程序提供基于角色、单点登录的安全性。为了启用 Windows 身份验证,我们需要将 IIS 目录设置配置为“集成 Windows 身份验证”。这将使 IIS 能够获取客户端凭据并将其传递给 ASP.NET 应用程序。
在本案例研究中,我们使用自定义 Windows 授权。通过使用 WindowsAuthentication_OnAuthenticate
事件处理程序,我们从 WindowsIdentity
对象创建了一个 GenericPrincipal
对象。选择自定义授权的原因如下:
- 应用程序角色与 Windows 组无关,并且
- 应用程序文件未按角色进行物理分组。
该应用程序还需要一些额外的“管理”屏幕来管理用户角色和身份验证信息。用户屏幕应显示所有来自“Active Directory”的用户名,以便管理员可以选择需要访问该应用程序的那些用户。此屏幕还应允许管理员为用户分配以下三个角色之一:“MD”、“CST”或“AM”。此信息存储在数据库的一个单独的“Users”表中。
在会话启动时,应用程序必须将 IIS 发送的客户端凭据与数据库中存储的凭据进行比较。如果找不到匹配项,它必须报告一次未经授权的访问尝试并退出应用程序。如果客户端凭据匹配,则会创建一个客户端 cookie,其中存储用户凭据和角色信息。对于后续请求,应用程序会利用此客户端 cookie,而不是命中数据库来验证客户端凭据。为了保护客户端 cookie,我们使用“用户身份”和“角色”信息创建一个 FormsAuthenticationTicket
。然后将此 FormsAuthenticationTicket
作为参数传递给 FormsAuthentication
类的 Encrypt
方法,以获取 FormsAuthenticationTicket
的加密字符串。然后,此字符串将存储在客户端 cookie 中。
在每次请求时,如果用户已通过身份验证,应用程序将创建一个安全 Principal
对象并将用户角色信息存储在其中。然后将此 Principal
对象放入 HttpContext.Current.User
。在每次 Page_Load
事件中,应用程序可以从 HttpContext.Current.User
访问 Principal
对象,并验证用户角色是否被授权访问该页面。
6.3. 实现细节
6.3.1. 配置应用程序的 IIS 安全设置
在应用程序的 IIS 安全设置中,勾选“集成 Windows 身份验证”,并取消勾选所有其他选项。
6.3.2. Windows 身份验证的 Web.Config 条目
在 Web.config 中,在 System.Web
标记下,添加以下条目:
<authenticationmode="Windows"/>
<authorization>
< allow users ="*" />
</authorization>
如果您想让子进程(例如:Web 服务)使用主线程的相同凭据,请使用以下条目:
<identityimpersonate="true"/>
6.3.3. 用户管理屏幕
如“解决方案架构”部分所述,应用程序应具有“用户管理”屏幕。通过此屏幕,管理员可以将 AD 用户名映射到应用程序角色。在此应用程序中,用户角色是预定义的硬编码值——“MD”、“CST”和“AM”。应用程序管理员可以直接输入 AD 用户名,或者应用程序可以显示所有 AD 用户名,以便管理员选择用户名。为了显示 AD 用户名,应用程序可以使用 .NET 基类 System.DirectoryServices
查询 Windows Active Directory。
6.3.4. 安全 Principal 对象
创建一个实现 System.Security.Principal.IPrincipal
接口的类。
using System;
using System.Security.Principal;
public class myAppPrincipal:IPrincipal
{
private IIdentity m_identity;
private string [] m_roles;
private string m_userId;
public MyAppPrincipal(IIdentity identity, string [] roles)
{
m_identity = identity;
m_roles = new string[roles.Length];
roles.CopyTo(m_roles, 0);
Array.Sort(m_roles);
m_userId = identity.Name;
}
public IIdentity Identity
{
get
{
return m_identity;
}
}
public string UserId
{
get
{
return m_userId;
}
set
{
m_userId = value;
}
}
public bool IsInRole(string role)
{
return Array.BinarySearch(m_roles, role) >=0 ? true : false;
}
}
6.3.5. 检查身份验证并确定角色
实施安全性的最重要部分是确保应用程序在每次请求时验证身份验证并确定用户角色。为此,我们利用以下全局应用程序级别事件:
WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
Application_AuthenticateRequest(Object sender, EventArgs e)
这些事件在每次请求时都会自动触发。
WindowsAuthentication_OnAuthenticate
最先触发。在相应的方法中,我们实现以下逻辑:
- 检查应用程序的
authenticationCookie
是否存在。如果存在,则从方法返回。如果不存在,则继续执行后续步骤。 - 提取 IIS 发送的 AD 用户名。它在事件参数中以
e.Identity.Name
的形式提供。 - 查询数据库,获取此用户名的应用程序角色。
- 创建一个 Forms Authentication Ticket,并在其中嵌入一个用户角色字符串。
- 创建一个新的
applicationauthenticationCookie
并将加密的 Forms Authentication Ticket 存储在其中。
在 Application_AuthenticateRequest
事件的方法中,执行以下操作:
- 读取
applicationauthenticationCookie
并重新创建 Forms Authentication Ticket。 - 从 Forms Authentication Ticket 中读取用户角色,并创建一个包含这些用户角色的
Principal
对象。 - 将此
Principal
对象存储在HttpContext.Current.User
中。
以下代码显示了这些任务的实现:
protected void WindowsAuthentication_OnAuthenticate(Object source,
WindowsAuthenticationEventArgs e)
{
if(Request.Cookies.Get("authCookie") != null)
return;
string strUserIdentity;
string strUserRoles;
FormsAuthenticationTicket formsAuthTicket;
HttpCookie httpCook;
String strEncryptedTicket;
strUserIdentity = e.Identity.Name;
strUserRoles = GetUserRoles(strUserIdentity); // "MD|CST|AM" from DB
formsAuthTicket = new FormsAuthenticationTicket(1, strUserIdentity, DateTime.Now,
DateTime.Now.AddMinutes(60), false, strUserRoles);
strEncryptedTicket = FormsAuthentication.Encrypt(formsAuthTicket);
httpCook = new HttpCookie("authCookie", strEncryptedTicket);
Response.Cookies.Add(httpCook);
}
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
FormsAuthenticationTicket formsAuthTicket;
HttpCookie httpCook;
GenericIdentity objGenericIdentity;
myAppPrincipal objMyAppPrincipal;
string[] strRoles;
httpCook = Context.Request.Cookies.Get("authCookie");
formsAuthTicket = FormsAuthentication.Decrypt(httpCook.Value);
objGenericIdentity = new GenericIdentity(formsAuthTicket.Name);
strRoles = formsAuthTicket.UserData.Split('|');
objMyAppPrincipal = new myAppPrincipal(objGenericIdentity, strRoles);
HttpContext.Current.User = objMyAppPrincipal;
}
6.3.6. 检查基于角色的授权
在每个 Web 页面的 Page_Load
中,检查 HttpContext.Current.User
中当前用户角色是否被允许访问该页面。如果不允许,则重定向到一个显示消息“您无权查看此页面”的通用页面。
7. 总结
- 提供应用程序安全是确保信息安全的重要方面。
- 身份验证有助于验证用户是否确实是他/她声称的那个人。应用程序从用户获取凭据(各种形式的身份验证,如姓名和密码),并根据某个权威机构验证这些凭据。如果凭据有效,则提交凭据的实体被视为已通过身份验证的身份。授权通过授予或拒绝已通过身份验证的身份特定的权限来限制访问权限。
- ASP.NET 使用 Windows 身份验证与 Microsoft Internet Information Services (IIS) 身份验证结合使用。当 IIS 身份验证完成后,ASP.NET 使用已通过身份验证的身份来授权访问。
- 在 ASP.NET 中,Windows 身份验证可以与“Windows 角色”基于授权或“自定义授权”结合使用。在“Windows 角色”基于授权中,根据 web.config 中的设置,授予/拒绝 Windows 用户/组对应用程序文件夹的访问权限。而在“自定义授权”中,此逻辑是以编程方式实现的。
8. 缩略语
缩写 | 展开 |
AD | Active Directory |
IIS | Internet 信息服务 |
MD | 主数据 |
CST | 中央支持团队 |
AM | 区域经理 |