ASP.NET 安全性

类别:.NET开发 点击:0 评论:0 推荐:

本章内容

ASP.NET 是开发本指南所讨论的分布式 Web 应用程序的重心。它提供丰富而且容易访问的安全能力级,从而方便了安全的 Web 应用程序的创建。ASP.NET 被设计成与 Internet Information Services (IIS) 的现有安全能力相兼容,但同时它也非常灵活,而且可以扩展。这意味着您可以构建与自己的应用程序紧密集成的自定义安全机制。

本章提供指南和建议来帮助您解决在构建安全的 ASP.NET Web 应用程序时碰到的身份验证、授权和安全通信等问题。

本章所提供的大多数指南和建议同样适用于开发 ASP.NET Web 服务和由 ASP.NET 托管的 .NET Remoting 对象。

目标

利用本章来:

保护您的 ASP.NET 应用程序。

保护由 ASP.NET 应用程序维护的机密和状态信息。

理解 ASP.NET 应用程序的安全体系结构,并了解 IIS、Windows、.NET Framework 和ASP.NET 的安全能力如何协调工作,从而为您的分布式 Web 应用程序提供安全性。

选择一种适合于您的应用程序的身份验证和授权策略。

理解 ASP.NET 进程标识和模拟对您的应用程序访问下游资源(如文件和数据库)的能力的影响。

结合使用产品配置工具和编程技术来为您的 ASP.NET Web 应用程序实现安全设计。

适用于

本章适用于以下产品和技术:

Microsoft® Windows® Server 2000 和 ™ 2003 操作系统

Microsoft Internet Information Services 5.0 和更高版本

Microsoft Active Directory® 目录服务

Microsoft .NET Framework 1.0 版(带 service pack 2)

Microsoft Visual Studio® 1.0 .NET 开发系统和更高版本

Microsoft Visual C#® .NET 开发工具

Microsoft SQL Server™ 2000 (带 service pack 2)和更高版本

如何使用本章

要想从本单元获得最大价值,您必须:

具有使用Visual C# .NET 和 Visual Studio .NET 进行编程的经验。

具有开发和配置 ASP.NET Web 应用程序的经验。

具有配置 IIS 安全性的经验。

具有使用 Windows 管理工具配置 Windows 安全性和创建用户帐号的经验。

具有配置 Active Directory 的经验。

具有开发和配置 Enterprise Services (COM+) 应用程序的经验。

阅读“Introduction”一章。它定义了身份验证、授权和安全通信对分布式 Web 应用程序的重要性。

阅读“Security Model for ASP.NET Applications”一章。它概述了创建分布式 ASP.NET Web 应用程序所使用的体系结构和技术,并着重指出该体系结构的什么位置适用身份验证、授权和安全通信。

阅读“身份验证和授权”一章。它介绍您在使用 ASP.NET 时可用的身份验证和授权机制。

阅读“Secure Communication”一章。它介绍可用于保护 ASP.NET 与分布式 Web 应用程序之间的通信的各种技术。

阅读以下各章,它们提供循序渐进的过程,为您显示如何实现本章所讨论的许多技术:

How To Create a Custom Account to run ASP.NET

How To Set Up SSL on a Web Server

How To Use SSL to Secure Communication with SQL Server 2000

How To Use IPSec to Provide Secure Communication Between Two Servers

How To Implement IPrincipal

How To Use Forms Authentication with SQL Server 2000

How To Use Forms Authentication with Active Directory

How To Create GenericPrincipal Objects with Forms Authentication

How To Implement Kerberos Delegation for Windows 2000

本页内容
ASP.NET 安全体系结构 ASP.NET 安全体系结构
身份验证和授权策略 身份验证和授权策略
配置安全性 配置安全性
编程安全性 编程安全性
Windows 身份验证 Windows 身份验证
窗体身份验证 窗体身份验证
无 Cookie 窗体身份验证 无 Cookie 窗体身份验证
更多信息 更多信息
Passport 身份验证 Passport 身份验证
自定义身份验证 自定义身份验证
ASP.NET 的进程标识 ASP.NET 的进程标识
模拟 模拟
访问系统资源 访问系统资源
访问 COM 对象 访问 COM 对象
访问网络资源 访问网络资源
安全通信 安全通信
存储机密 存储机密
保护会话和视图状态 保护会话和视图状态
网络场注意事项 网络场注意事项
小结 小结

ASP.NET 安全体系结构

ASP.NET 与 IIS、.NET Framework 和操作系统所提供的基础安全服务配合使用,共同提供一系列身份验证和授权机制。图 1 总结了这些机制。

f08sn01

图 1. ASP.NET 安全服务

图 1 阐释了 IIS 和 ASP.NET 所提供的身份验证和授权机制。当客户端发出 Web 请求时,就会发生以下一系列身份验证和授权事件:

1.

接收来自网络的 HTTP(S) Web 请求。可以使用 SSL 确保服务器身份(使用服务器证书)和客户端身份(可选)的安全。

SSL 还提供了一个安全通道,以便保护在客户端和服务器之间传递的机密数据。

2.

IIS 使用基本、简要、集成(NTLM 或 Kerberos)或证书身份验证方式验证调用者的身份。如果站点的所有或部分内容不需要通过身份验证即可访问,则可将 IIS 配置为使用匿名身份验证。IIS 为每个通过身份验证的用户创建一个 Windows 访问令牌。如果选择匿名身份验证,则 IIS 为该匿名 Internet 用户帐号(默认为 IUSR_MACHINE)创建访问令牌。

3.

IIS 授权调用者访问所请求的资源。使用附加到所请求资源的 ACL 定义的 NTFS 权限授权访问。IIS 也可以配置为只接受来自特定 IP 地址的客户端计算机的请求。

4.

IIS 将通过身份验证的调用者的 Windows 访问令牌传递给 ASP.NET (如果使用匿名身份验证,则它可能是匿名 Internet 用户的访问令牌)。

5.

ASP.NET 验证调用者的身份。

如果 ASP.NET 配置为使用 Windows 身份验证,则此时不会发生任何其他的身份验证。ASP.NET 将接受它从 IIS 接收的任何令牌。

如果 ASP.NET 配置为使用窗体身份验证,则将根据数据存储(通常为 SQL Server 数据库或 Active Directory 目录服务)对调用者提供的凭证进行身份验证(使用 HTML 窗体)。如果 ASP.NET 配置为使用 Passport 身份验证,则将用户重定向到 Passport 站点,然后 Passport 身份验证服务对用户进行身份验证。

6.

ASP.NET 授权访问所请求的资源或操作。

UrlAuthorizationModule(系统提供的 HTTP 模块)使用在 Web.config 中配置的授权规则(具体来讲就是 <authorization> 元素),确保调用者可以访问所请求的文件或文件夹。

在 Windows 身份验证下,FileAuthorizationModule(另一个 HTTP 模块)会检查调用者是否具有访问所请求资源的必要权限。将调用者的访问令牌与保护资源的 ACL 进行比较。

也可以使用 .NET 角色(以声明方式或编程方式)确保调用者被授权访问所请求的资源或执行所请求的操作。

7.

应用程序中的代码使用特定标识来访问本地和/或远程资源。默认情况下,ASP.NET 不执行模拟,因此,由配置好了的 ASP.NET 进程帐号提供标识。也可以选择原调用者的标识(如果启用了模拟)或已配置的服务标识。

网关守卫

ASP.NET Web 应用程序中的授权点或网关守卫是由 IIS 和 ASP.NET 提供的:

IIS

如果关闭了匿名身份验证,则 IIS 只允许来自特定用户的请求,即它可以在其自己的域或受信任域中验证这些用户的身份。

对于静态文件类型(例如 .jpg、.gif 和 .htm 文件,即没有映射到 ISAPI 扩展的文件),IIS 使用与所请求的文件相关的 NTFS 权限来执行访问控制。

ASP.NET

ASP.NET 网关守卫包括 UrlAuthorizationModuleFileAuthorizationModule 和主体权限要求和角色检查。

UrlAuthorizationModule

可以配置应用程序 Web.config 文件中的 <authorization> 元素来控制哪些用户和用户组可以访问应用程序。授权是基于存储在 HttpContext.User 中的 IPrincipal 对象进行的。

FileAuthorizationModule

对于被 IIS 映射到 ASP.NET ISAPI 扩展(Aspnet_isapi.dll) 的文件类型,使用已验证用户的 Windows 访问令牌(可能是 IUSR_MACHINE),根据附加到所请求的 ASP.NET 文件的 ACL 自动执行访问检查。

要进行文件授权,并不要求模拟。

FileAuthorizationModule 类只对所请求的文件执行访问检查,而不对所请求的页面中的代码所访问的文件执行访问检查,但 IIS 对这些文件执行访问检查。

例如,如果您请求 Default.aspx,并且它包含一个嵌入的用户控件(Usercontrol.ascx),而该控件又包含一个图像标签(指向 Image.gif),则 FileAuthorizationModule 会对 Default.aspx 和 Usercontrol.ascx 执行访问检查,因为 IIS 将这些文件类型映射到 ASP.NET ISAPI 扩展。

FileAuthorizationModule 不对 Image.gif 执行访问检查,因为它是由 IIS 内部处理的静态文件。然而,由于 IIS 对静态文件执行访问检查,所以仍然使用进行相应配置的 ACL 对已验证用户授予读取该文件的权限。

图 2 显示了此方案。

对于系统管理员:需要给已通过身份验证的用户授予读取此方案中涉及的所有文件的 NTFS 权限。惟一的变化是使用哪个网关守卫来执行访问控制。ASP.NET 进程帐号只需要读取 ASP.NET 注册文件类型的访问权限。

f08sn02

图 2. IIS 和 ASP.NET 网关守卫一起使用

在此方案中,您可以在文件入口处禁止访问。如果您配置了附加到 Default.aspx 的 ACL,并且拒绝访问某个特定的用户,则 Default.aspx 中的代码无法将用户控件或任何嵌入图像发送到客户端。如果该用户直接请求图像,则 IIS 亲自执行访问检查。

主体权限要求和明确的角色检查

除了可以用 IIS 和 ASP.NET 配置的网关守卫外,还可以将主体权限要求(以声明方式或编程方式)用作附加的细分访问控制机制。通过使用主体权限检查(由 PrincipalPermissionAttribute 类执行),您可以根据各个用户的标识和组成员身份(由附加到当前线程的 IPrincipal 对象定义)控制访问类、方法或个别代码块。

用于请求角色成员身份的主体权限要求与调用 IPrincipal.IsInRole 来测试角色成员身份不同;如果调用者不是指定角色的成员,则前者产生异常,而后者仅返回一个布尔值来确认角色成员身份。

在 Windows 身份验证中,ASP.NET 自动将一个代表已验证身份用户的 WindowsPrincipal 对象连接到当前的 Web 请求(使用 HttpContext.User)。窗体和 Passport 身份验证创建具有相应标识但没有角色的 GenericPrincipal 对象,并将它附加到 HttpContext.User

更多信息

有关配置安全性的详细信息,请参见本章后面的“配置安全性”。

有关编程安全性(和 IPrincipal 对象)的详细信息,请参见本章后面的“编程安全性”。

身份验证和授权策略

ASP.NET 提供了若干以声明方式和编程方式进行授权的机制,这些机制可与各种身份验证方案配合使用。这样,您就可以开发深入的授权策略以及可以配置为提供各种粒度级别(例如,基于角色的每用户或每用户组)的授权策略。

本节说明一组常用身份验证选项的可用授权选项(可进行配置和编程)。

下面概述了身份验证选项:

带模拟的 Windows 身份验证

不带模拟的 Windows 身份验证

使用固定身份的 Windows 身份验证

窗体身份验证

Passport 身份验证

可用的授权选项

下表列出了一组可用的授权选项。对于每个选项,该表都指出是否需要 Windows 身份验证和/或模拟。如果特定授权选项不需要 Windows 身份验证,则该选项适用于所有其他的身份验证类型。可以使用该表优化身份验证/授权策略。

表 1:Windows 身份验证和模拟要求
授权选项 需要 Windows 身份验证 需要模拟

FileAuthorizationModule

UrlAuthorizationModule

Principal Permission Demands

.NET Roles

Enterprise Services Roles

是(在 ASP.NET Web 应用程序中)

NTFS 权限(用于直接请求的静态文件类型;没有映射到 ISAPI 扩展的文件类型)

不适用— ASP.NET 不处理这些文件。
在任何(非匿名)IIS 身份验证机制中,应为各个已验证的用户配置权限。
在匿名身份验证中,应为 IUSR_MACHINE 配置权限。

否(IIS 执行访问检查。)

NTFS 权限(用于 Web 应用程序代码访问的文件)


如果使用模拟,请根据模拟的 Windows 标识配置 ACL,该标识可以是原调用者,也可以是 Web.config 中的 <identity> 元素指定的标识。

带模拟的 Windows 身份验证

以下配置元素显示了如何明确启用 Web.config 或 Machine.config中的 Windows (IIS) 身份验证和模拟。

应根据每个应用程序的具体情况,在应用程序的 Web.config 文件中配置身份验证。

<authentication mode="Windows" />
<identity impersonate="true" />

在此配置中,ASP.NET 应用程序代码模拟已由 IIS 验证身份的调用者。

可配置的安全性

当您将 Windows 身份验证和模拟功能一起使用时,就可以使用下列授权选项:

WindowsACLs

客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用者的访问令牌和附加到请求资源的 ACL 以便执行访问检查。

对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用者的访问令牌和附加到文件的 ACL 执行访问检查。

应用程序访问的资源。可以根据原调用者,在应用程序访问的资源(文件、文件夹、注册表项和 Active Directory 对象等)上配置 Windows ACL。

URL 授权。在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 的格式,并且角色与 Windows 组 一 对应。

<authorization>
  <deny user="DomainName\UserName" />
  <allow roles="DomainName\WindowsGroup" />
</authorization>

Enterprise Services (COM+) 角色。角色保存在 COM+ 目录中。可以使用“组件服务”管理工具或脚本配置角色。

编程安全性

编程安全性是指 Web 应用程序代码中的安全检查。在您使用 Windows 身份验证和模拟功能时,可以使用下列程序安全设置选项:

PrincipalPermission 请求

命令性(嵌入方法的代码内)

PrincipalPermission permCheck = new PrincipalPermission(
                                       null, @"DomainName\WindowsGroup");
    permCheck.Demand();

声明性(属性位于接口、类和方法之前)

[PrincipalPermission(SecurityAction.Demand, 
                  Role=@"DomainName\WindowsGroup)]

明确的角色检查。您可以使用 IPrincipal 接口执行角色检查。

IPrincipal.IsInRole(@"DomainName\WindowsGroup");

Enterprise Services (COM+) 角色。可以使用 ContextUtil 类以编程方式执行角色检查。

ContextUtil.IsCallerInRole("Manager")

何时使用

使用 Windows 身份验证和模拟的情况:

应用程序的用户已经有了可以由服务器验证的 Windows 帐号。

您需要将原调用者的安全性上下文传递到 Web 应用程序的中间层和/或数据层以支持细分(每用户)授权。

您需要将原调用者的安全性上下文传递到下游各层以支持操作系统级审核。

在应用程序中使用模拟之前,确保将此方法与使用受信任的子系统模型进行比较,了解此方法的优缺点。“身份验证和授权”一章中的“授权方式”章节中的“选择资源访问模式”详细阐述了这些内容。

模拟的缺点包括:

由于无法对数据库连接进行池处理,因而降低了应用程序的可扩展性。

由于需要给各个用户配置后端资源的 ACL,因而增加了管理工作。

委派需要 Kerberos 身份验证和进行适当配置的环境。

更多信息

有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。

有关模拟的详细信息,请参见本章后面的“模拟”。

有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。

有关 Enterprise Services (COM+) 角色的详细信息,请参见“Enterprise Services Security一章。

不带模拟的 Windows 身份验证

下列配置元素显示了如何在Web.config.中明确声明启用不带模拟功能的 Windows(IIS) 身份验证。

<authentication mode="Windows" />
<!-- The following setting is equivalent to having no identity element -->
<identity impersonate="false" />

可配置的安全性

当您使用不带模拟的 Windows 身份验证时,可以使用以下授权选项:

WindowsACL

客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用者的访问令牌和附加到请求资源的 ACL 以便执行访问检查。模拟不是必需选项。

对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用者的访问令牌和附加到文件的 ACL 执行访问检查。

应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。

URL 授权。在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 格式,并且角色与 Windows 组 一 对应。

<authorization>
  <deny user="DomainName\UserName" />
  <allow roles="DomainName\WindowsGroup" />
</authorization>

程序安全性

可以使用下列编程安全选项:

主体权限要求

命令性

PrincipalPermission permCheck = new PrincipalPermission(
                                         null, @"DomainName\WindowsGroup");
    permCheck.Demand();

声明性

[PrincipalPermission(SecurityAction.Demand, 
                  Role=@"DomainName\WindowsGroup")]

明确的角色检查。您可以使用IPrincipal 接口执行角色检查。

IPrincipal.IsInRole(@"DomainName\WindowsGroup");

何时使用

使用不带模拟的 Windows 身份验证的情况:

应用程序的用户已经有了可以由服务器验证的 Windows 帐户。

需要使用固定标识来访问下游资源(例如数据库)以便支持连接池。

更多信息

有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。

有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。

使用固定标识的 Windows 身份验证

Web.config 中的 <identity> 元素支持可选的用户名和密码属性,这样,您就可以为应用程序配置特定的固定标识以进行模拟。这显示在以下配置文件片段中。

<identity impersonate="true"
          userName="registry:HKLM\SOFTWARE\YourSecureApp\
                    identity\ASPNET_SETREG,userName"
          password="registry:HKLM\SOFTWARE\YourSecureApp\
                    identity\ASPNET_SETREG,password" />

这个例子显示了 <identity> 元素,其中凭证在注册表中使用 aspnet_setreg.exe 工具进行加密。明文形式的 userNamepassword 属性值被指向安全的注册表项和包含加密凭证的命名值的指针所替代。有关这个工具的详细信息及下载方式,请参见 Microsoft 知识库中的文件 Q329290 “HOWTO:Use the ASP.NET Utility to Encrypt Credentials and Session State Connection Strings”。

何时使用

当在运行 Windows 2000 的服务器上使用 .NET Framework 1.0 时,不建议使用固定的模拟标识。因为这需要您授予 ASP.NET 进程帐户“充当操作系统的一部分”权限,这个权限很大。 ASP.NET 进程需要这个权限,因为它使用您所提供的凭证执行 LogonUser 调用。

.NET 框架 1.1 版将在 Windows 2000 上提供此方案的改进版本。凭证将由 IIS 进程执行,这样 ASP.NET 就不需要“充当操作系统的一部分”权限了。

窗体身份验证

以下配置元素显示了如何在 Web.config 中以声明方式启用窗体身份验证。

<authentication mode="Forms">
  <forms loginUrl="logon.aspx" name="AuthCookie" timeout="60" path="/">
  </forms>
</authentication>

可配置的安全性

在使用窗体身份验证时,可以使用以下授权选项:

WindowsACL

客户端请求的资源。请求的资源需要 ACL 以允许对匿名 Internet 用户帐户进行读取访问。(在使用窗体身份验证时,应该将 IIS 配置为允许匿名访问)。

无法使用 ASP.NET 文件授权,因为它需要 Windows 身份验证。

应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。

URL 授权

在 Web.config 中配置 URL 授权。在窗体身份验证中,用户名的格式取决于自定义数据存储、SQL Server 数据库或 Active Directory。

如果使用的是 SQL Server 数据存储,则为:

<authorization>
<deny users="?" />
  <allow users="Mary,Bob,Joe" roles="Manager,Sales" />
</authorization>

如果使用 Active Directory 作为数据存储,则以 X.500 格式显示用户名和组名:

<authorization>
  <deny users="[email protected]" />
  <allow roles ="CN=Smith James,CN=FTE_northamerica,CN=Users,
                DC=domain,DC=corp,DC=yourCompany,DC=com" />
</authorization>

程序安全性

可以使用下列编程安全选项:

主体权限要求

命令性

PrincipalPermission permCheck = new PrincipalPermission(
                                         null, "Manager");
    permCheck.Demand();

声明性

[PrincipalPermission(SecurityAction.Demand, 
                  Role="Manager")]

明确的角色检查。您可以使用 IPrincipal 接口执行角色检查。

IPrincipal.IsInRole("Manager");

何时使用

窗体身份验证最适合于 Internet 应用程序。如果出现以下情况,则应该使用窗体身份验证:

应用程序用户没有 Windows 帐户。

您希望用户通过使用 HTML 窗体输入凭证的方式登录到应用程序。

更多信息

有关窗体身份验证的详细信息,请参见本章后面的“窗体身份验证“。

有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。

Passport 身份验证

以下配置元素显示了如何在 Web.config 中以声明方式启用 Passport 身份验证。

<authentication mode="Passport" />

何时使用

如果应用程序用户没有 Windows 帐户,并且您希望实现单次登录解决方案,则应该在 Internet 上使用 Passport 身份验证。如果用户以前使用 Passport 帐户在参与的 Passport 站点进行登录,则不必登录到使用 Passport 身份验证配置的站点。

配置安全性

本节说明配置 ASP.NET Web 应用程序安全性所需的实际步骤。 3 总结了这些情况。

F08sn03_t

3. 配置 ASP.NET 应用程序安全性

配置 IIS 设置

要配置 IIS 安全性,您必须执行以下步骤:

1.

(可选)安装 Web 服务器证书(如果需要 SSL 的话)。 有关详细信息,请参见“How To Set Up SSL on a Web Server”。

2.

配置 IIS 身份验证。

3.

(可选)配置客户端证书映射(如果使用证书身份验证的话)。

有关客户端证书映射的详细信息,请参见 Microsoft 知识库文章 Q313070“How To:Configure Client Certificate Mappings in Internet Information Services (IIS) 5.0”。

4.

设置文件和文件夹的 NTFS 权限。IIS 和 ASP.NET FileAuthorizationModule 共同检查已验证用户(或匿名 Internet 用户帐户)是否具有访问所请求文件的必要权限(根据 ACL 设置)。

配置 ASP.NET 设置

应用程序级别配置设置保存在 Web.config 文件中,这些文件位于应用程序的虚拟根目录或者(可选)其他子文件夹中(这些设置有时可以覆盖父文件夹设置)。

1.

配置身份验证。应该在应用程序虚拟根目录下的 Web.config 文件中基于每个应用程序对它进行设置(而不是在 Machine.config 中)。

<authentication mode="Windows|Forms|Passport|None" />

2.

配置模拟。默认情况下,ASP.NET 应用程序不使用模拟。应用程序使用配置的 ASP.NET 进程标识(通常为 ASPNET)运行,并且应用程序执行的所有资源访问都使用此标识。仅在以下情况下需要使用模拟:

您使用 Enterprise Services,并且要使用 Enterprise Services (COM+) 角色授权访问服务组件所提供的功能。

将 IIS 配置为使用匿名身份验证,而且要使用匿名 Internet 用户帐户进行资源访问。有关此方法的详细信息,请参见本章后面的“访问网络资源”。

您需要将已验证用户的安全性上下文传递到下一层(例如数据库)。

您已将传统的 ASP 应用程序移植到 ASP.NET,并且需要同样的模拟行为。默认情况下,传统 ASP 模拟调用者。

要配置 ASP.NET 模拟,请在应用程序的 Web.config 中使用下面的 <identity> 元素。

<identity impersonate="true" />

3.

配置授权。URL 授权确定用户或角色是否可以将特定的 HTTP 谓词(例如,GET、HEAD 和 POST)发送给特定的文件。要实现 URL 授权,请执行以下任务。

1.

将 <authorization> 元素添加到应用程序虚拟根目录下的 Web.config 文件中。

2.

使用 allowdeny 属性限制对用户和角色的访问。下面的示例摘自 Web.config,它使用 Windows 身份验证并允许 Bob 和 Mary 访问,但拒绝其他人访问。

<authorization>
  <allow users="DomainName\Bob, DomainName\Mary" />
  <deny users="*" />
</authorization>

重要 您需要在 <authorization> 元素的结尾添加 <denyusers="?"> 或 <denyusers="*">,否则将给所有已验证的标识授予访问权限。

URL 授权注意事项

在配置 URL 授权时,请注意以下几点:

"*" 指所有标识。

"?" 指未通过身份验证的标识(即匿名标识)。

要使 URL 授权能够正常工作,并不需要进行模拟。

Web.config 中的授权设置通常适用于当前目录和所有子目录中的所有文件(除非子目录包含它自己的 Web.config,并且该文件包含 <authorization> 元素。在这种情况下,子目录中的设置覆盖父目录的设置)。

URL 授权只适用于由 IIS 映射到 ASP.NET ISAPI (spnet_isapi.dll) 的文件类型。

可以使用 <location> 标记将授权设置应用于个别文件或目录。下面的示例显示了如何将授权应用于特定的文件 (Page.aspx)。

<location path="page.aspx" />
  <authorization>
    <allow users="DomainName\Bob, DomainName\Mary" />
    <deny users="*" />
  </authorization>
</location>

用于 URL 授权的用户和角色是由身份验证设置决定的:

如果设置了 <authenticationmode="Windows" >,则给 Windows 用户和组帐户授予访问权限。 用户名采用“DomainName\WindowsUserName”格式 角色名采用“DomainName\WindowsGroupName”格式

本地管理员组称为“BUILTIN\Administrators”。本地用户组称为“BUILTIN\Users”。

如果设置了 <authenticationmode="Forms" >,则根据存储在当前 HTTP 上下文中的 IPrincipal 对象的用户和角色进行授权。例如,如果使用窗体身份验证根据数据库验证用户的身份,则根据从数据库中检索的角色进行授权。

如果设置了 <authenticationmode="Passport" >,则根据从存储中检索的 Passport User ID (PUID) 或角色进行授权。例如,可以将 PUID 映射到特定的帐户和在 SQL Server 数据库或 Active Directory 中存储的一组角色。

此功能被内置到 Microsoft Windows .NET Server 2003 操作系统中。

如果设置了 <authenticationmode="None" >,则不能执行授权。"None" 指定您不想执行任何身份验证,或者不想使用任何 .NET 身份验证模块,而是使用自己的自定义机制。

但是,如果使用自定义身份验证,则应创建具有角色的 IPrincipal 对象,并将其存储到 HttpContext.User 中。在随后执行 URL 授权时,将根据 IPrincipal 对象中保存的用户和角色(无论以何种方式检索它们)执行授权。

URL 授权示例

以下列表列出了一些典型 URL 授权示例的语法:

拒绝匿名帐户访问

<deny users="?" />

拒绝所有用户访问

<deny users="*"/>

拒绝 Manager 角色访问

<deny roles="Manager"/>

窗体身份验证示例

<configuration>
  <system.web>
      <authentication mode="Forms">
        <forms name=".ASPXUSERDEMO" 
               loginUrl="login.aspx" 
               protection="All" timeout="60" />
      </authentication>
      <authorization>
        <deny users="[email protected]" />
        <deny users="?" />
      </authorization>
  </system.web>
</configuration>

<authorization> 元素可用于存储在 HttpContext.User 中的当前 IPrincipal 对象,也可用于存储在 HttpContext.Request.RequestType 中的 HTTP 数据传输方法。

保护资源

1.

使用 Windows ACL 保护资源,包括文件、文件夹和注册表项。

如果不使用模拟,则应用程序需要访问的任何资源的 ACL 必须授予 ASP.NET 进程帐户至少“读”访问权限。

如果使用模拟,文件和注册表项的 ACL 必须授予已验证用户(或匿名 Internet 用户帐户,如果匿名身份验证生效的话)至少“读”访问权限。

2.

保护 Web.config 和 Machine.config:

使用正确的 ACL。如果 ASP.NET 使用模拟,则模拟的标识需要“读”访问权限。否则,ASP.NET 进行标识需要“读”访问权限。对 Web.config 的 Machine.config 使用以下 ACL。

系统:完全控制

管理员:完全控制

进程标识或模拟的标识:读

如果没有模拟匿名 Internet 用户帐户 (IUSR_MACHINE),则应该拒绝该帐户的访问。

如果将应用程序映射到 UNC 共享,则 UNC 标识也需要读取配置文件的访问权限。

删除不需要的 HTTP 模拟。Machine.config 包含一组默认的 HTTP 模拟(在 <httpModules> 元素内)。它们是:

WindowsAuthenticationModule

FormsAuthenticationModule

PassportAuthenticationModule

UrlAuthorizationModule

FileAuthorizationModule

OutputCacheModule

SessionStateModule

如果应用程序没有使用特定的模拟,请将其删除,以免将来在应用程序中出现与该模拟有关的任何潜在的安全问题。

3.

(可选)将 <location> 元素与 allowOverride="false" 属性一起使用以锁定配置设置,如下所示。

锁定配置设置

配置设置是分层的。子目录中的 Web.config 文件设置覆盖父目录中的 Web.config 设置。另外,Web.config 设置覆盖 Machine.config 设置。

通过将 <location> 元素与 allowOverride 属性一起使用,可以锁定配置设置以防止它们被低级别的设置覆盖。例如:

<location path="somepath" allowOverride="false" />
 . . . arbitrary configuration settings . . .
</location>

请注意:路径可以指 Web 站点或虚拟目录,并且它适用于指定的目录和所有子目录。如果将 allowOverride 设置为 false,则可以防止任何低级别的配置文件覆盖 <location> 元素中指定的位置。锁定配置设置的功能适用于所有设置类型,而不仅限于安全设置(如身份验证模式)。

在 machine.config 的上下文中,路径必须为全资格的,并且包含 Web 站点、虚拟目录名称和(可选)一个子目录和文件名。例如:

<location path="Web Site Name/VDirName/SubDirName/PageName.aspx" >
 . . .
</location>

在 Web.config 的上下文中,路径只与应用程序的虚拟目录有关。例如:

<location path="SubDirName/PageName.aspx" >
. . .
</location>

禁止下载文件

可以使用 HttpForbiddenHandler 类禁止通过 Web 下载某些文件类型。该类由 ASP.NET 在内部使用以禁止下载某些系统级文件(例如,包括 Web.config 在内的配置文件)。有关以这种方式进行限制的文件类型的完整列表,请参见 machine.config 中的 <httpHandlers> 部分。

对于应用程序在内部使用但不能进行下载的文件,应考虑使用 HttpForbiddenHandler

还必须使用 Windows ACL 来保护文件,控制哪些用户在登录到 Web 服务器上时可以访问这些文件。

使用 HttpForbiddenHandler 禁止下载特定的文件类型

1.

在 IIS 中为指定的文件类型创建应用程序映射,以便将其映射到 Aspnet_isapi.dll。

1.

在任务栏上,依次单击“开始”按钮、单击“程序”,单击“管理工具”然后选择“Internet 信息服务”。

2.

选择应用程序的虚拟目录,右击,然后单击“属性”。

3.

选择“应用程序设置”,然后单击“配置”。

4.

单击“添加”以创建新的应用程序映射。

5.

单击“浏览”,然后选择c:\winnt\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll。

6.

在“扩展”字段中键入要禁止下载的文件类型的扩展名(例如,.abc)。

7.

确保选中“所有版本”和“脚本引擎”,并且不选择“该文件是否存在”。

8.

单击 OK 关闭“添加/编辑应用程序扩展映射”对话框。

9.

单击 OK 关闭“应用程序配置”对话框,然后再单击 OK 关闭“属性”对话框。

2.

在 Web.config 中,为指定的文件类型添加 <HttpHandler> 映射。

下面显示了一个 .abc 文件类型的示例。

<httpHandlers>
  <add verb="*" path="*.abc" 
    type="System.Web.HttpForbiddenHandler"/>
</httpHandlers>

安全通信

结合使用 SSL 和 Internet 协议安全 (IPSec) 以保护通信链路。

更多信息

有关使用 SSL 保护数据库服务器链路的信息,请参见“How To Use SSL to Secure Communication with SQL Server 2000”。

有关在两台计算机之间使用 IPSec 的信息,请参见“How To Use IPSec to Provide Secure Communication Between Two Servers”。

编程安全性

在确定 Web 应用程序可配置的安全设置后,您需要以编程方式进一步改进和优化应用程序的授权策略。这包括在程序集中使用声明性的 .NET 属性,以及在代码中执行命令性的授权检查。

本节重点介绍在 ASP.NET Web 应用程序中执行授权所需的主要编程步骤。

授权模式

下面总结了在 Web 应用程序中对用户进行授权的基本模式:

1.

检索凭证

2.

检验凭证

3.

将用户放到角色中

4.

创建一个 IPrincipal 对象

5.

IPrincipal 对象放到当前的 HTTP 上下文中

6.

基于用户标识/角色成员身份进行授权

重要 如果配置了 Windows 身份验证,则 ASP.NET 自动执行步骤 1 到 5。对于其他身份验证机制(窗体、Passport 和自定义方法),您必须编写代码以执行这些步骤(如下所示)。

检索凭证

首先,必须从用户检索一组凭证(用户名和密码)。如果应用程序没有使用 Windows 身份验证,则需要确保使用 SSL 在网络上正确保护明文凭证。

检验凭证

如果配置了 Windows 身份验证,则操作系统的基本服务就会自动对凭证进行检验。

如果使用其他身份验证机制,则必须编写代码以根据数据存储(如 SQL Server 数据库或 Active Directory)对凭证进行检验。

有关如何将用户凭证安全地存储在 SQL Server 数据库中的详细信息,请参见“数据访问安全性”一章中的“对数据库进行用户身份验证”。

将用户放到角色中

用户数据存储还应包含每个用户的角色列表。必须编写代码以检索已检验用户的角色列表。

创建一个 IPrincipal 对象

授权是针对已验证用户进行的,这些用户的标识和角色列表保存在 IPrincipal 对象中(该对象在当前 Web 请求的上下文中传递)。

如果配置了 Windows 身份验证,则 ASP.NET 会自动构造 WindowsPrincipal 对象。该对象包含已验证用户的标识以及角色列表(它等同于用户所属的 Windows 组列表)。

如果使用的是窗体、Passport 或自定义身份验证,则必须在 Global.asax 的 Application_AuthenticateRequest 事件处理程序中编写代码以创建 IPrincipal 对象。GenericPrincipal 类是由 .NET 框架提供的,在大多数情况下应该使用此类。

将 IPrincipal 对象放到当前 HTTP 上下文中

IPrincipal 对象附加到当前 HTTP 上下文中(使用 HttpContext.User 变量)。如果使用 Windows 身份验证,则 ASP.NET 自动完成此任务。否则,您必须手动附加该对象。

基于用户标识和/或角色成员身份进行授权

如果应用程序需要更细分的授权逻辑,请在代码中以声明方式(获取类或方法级授权)或命令性方式使用 .NET 角色。

可以使用声明性或命令性主体权限要求(使用 PrincipalPermission 类),也 可以通过调用 IPrincipal.IsInRole() 方法执行明确的角色检查。

以下示例采用 Windows 身份验证并显示了声明性主体权限要求。仅当已验证用户是 Manager Windows 组的成员时,才执行该属性后面的方法。如果调用者不是该组的成员,就会发生 SecurityException

[PrincipalPermission(SecurityAction.Demand, 
                     Role=@"DomainName\Manager")]
public void SomeMethod()
{
}

以下示例显示代码中的明确角色检查。该示例采用 Windows 身份验证。如果使用非 Windows 身份验证机制,则代码基本上是一样的。只是将 User 对象转换成 WindowsPrincipal 对象,而不是 GenericPrincipal 对象。

// Extract the authenticated user from the current HTTP context.
// The User variable is equivalent to HttpContext.Current.User if you are using // an .aspx or .asmx page
WindowsPrincipal authenticatedUser = User as WindowsPrincipal;
if (null != authenticatedUser)
{
  // Note: To retrieve the authenticated user's username, use the 
  // following line of code
  // string username = authenticatedUser.Identity.Name;

  // Perform a role check
  if (authenticatedUser.IsInRole(@"DomainName\Manager") )
  {
    // User is authorized to perform manager functionality
  }
}
else
{
  // User is not authorized to perform manager functionality
}

更多信息

有关以上窗体身份验证模式的实现实现,请参见本章后面的“窗体身份验证”部分。

创建自定义的 IPrincipal 类

当您使用非 Windows 身份验证机制时,大多数情况下应使用 .NET 框架提供的 GenericPrincipal 类。它使用 IPrincipal.IsInRole 方法提供角色检查。

有时,您可能需要实现自己的 IPrincipal 类。实现您自己的 IPrincipal 的原因有:

您想扩展角色检查功能。您可能需要一些方法来使您能够检查某个特定用户是否是一个多角色成员。例如:

CustomPrincipal.IsInAllRoles( "Role", "Role2", "Role3" )
CustomPrincipal.IsInAnyRole( "Role1", "Role2", "Role3" )

您可能需要实现一个额外的方法或属性,以数组形式返回角色列表。例如:

string[] roles = CustomPrincipal.Roles;

您想让应用程序强制实施角色分级逻辑。例如,高级管理员被认为在层次结构中高于普通管理员。可以用类似下面所示的方法进行测试。

CustomPrincipal.IsInHigherRole("Manager");
CustomPrincipal.IsInLowerRole("Manager");

您可能需要实现惰性的角色列表初始化。例如,只有在需要进行角色检查时,才能动态加载角色列表。 您可能需要实现 IIdentity 接口以使用 X509ClientCertificate 标识的用户。例如:

CustomIdentity id = CustomPrincipal.Identity;
X509ClientCertificate cert = id.ClientCertificate;

更多信息

有关创建您自己的 IPrincipal 类的详细信息,请参见“How To Implement IPrincipal”。

Windows 身份验证

如果应用程序用户使用可由服务器进行身份验证的 Windows 帐户(例如,在 Intranet 方案中),请使用 Windows 身份验证。

如果将 ASP.NET 配置为使用 Windows 身份验证,则 IIS 使用配置的 IIS 身份验证机制执行用户身份验证。 4 显示了这种情况。

f08sn04

4. ASP.NET Windows 身份验证使用 IIS 验证调用者的身份

已验证调用方(如果将 IIS 配置为使用匿名身份验证,则它可能是匿名 Internet 用户帐户)的访问令牌可供 ASP.NET 应用程序使用。请注意以下方面:

这将允许 ASP.NET FileAuthorizationModule 使用原调用者的访问令牌,对请求的 ASP.NET 文件执行访问检查。

重要 ASP.NET 文件授权只对映射到 Aspnet_isapi.dll 的文件类型执行访问检查。

文件授权不要求使用模拟。如果启用了模拟,则应用程序执行的所有资源访问均使用被模拟的调用者的标识。在这种情况下,请确保附加到资源上的 ACL 包含一个访问控制项 (ACE),它可授予原调用者标识至少“读”访问权限。

标识已验证身份的用户

ASP.NET 将 WindowsPrincipal 对象与当前的 Web 请求关联起来。这包含已验证身份的 Windows 用户的标识以及该用户所属的角色列表。在 Windows 身份验证中,角色列表是由用户所属的 Windows 组集组成的。

以下代码显示如何获取已验证 Windows 用户的标识,以及如何执行简单的角色授权测试。

WindowsPrincipal user = User as WindowsPrincipal;
if (null != user)
{
  string username = user.Identity.Name;
  // Perform a role check
  if ( user.IsInRole(@"DomainName\Manager") )
  {
    // User is authorized to perform manager functionality
  }
}
else
{
  // Throw security exception as we don't have a WindowsPrincipal
}  

窗体身份验证

当使用窗体身份验证时,如果未验证身份的用户试图访问受保护的文件或资源(其中,URL 授权拒绝用户访问),该用户所触发的事件顺序如 5 所示。

f08sn05

5. 窗体身份验证的事件顺序

以下描述 5 所示的事件顺序:

1.

用户发出一个针对 Default.aspx 的 Web 请求。

由于启用了匿名访问,所以 IIS 允许此类请求。ASP.NET 检查 <authorization> 元素并查找 <denyusers=?" > 元素。

2.

将用户重定向到由 <forms> 元素的 loginUrl 属性指定的登录页 (Login.aspx)。

3.

用户提供凭证并提交登录窗体。

4.

根据数据存储(SQL Server 或 Active Directory)检验凭证,并检索角色(可选)。如果要使用基于角色的授权,则必须检索角色列表。

5.

使用 FormsAuthenticationTicket 创建一个 Cookie 并将其发回客户端。将角色存储到票证中。通过在票证中存储角色列表,可以避免为相同用户的每个后续 Web 请求访问数据库重新检索列表。

6.

客户端重定向将用户重定向到原请求页 (Default.aspx)。

7.

Application_AuthenticateRequest 事件处理程序(位于 Global.asax)中,使用票证创建 IPrincipal 对象并将其存储在 HttpContext.User 中。

ASP.NET 检查 <authorization> 元素并查找 <denyusers=?" > 元素。但此时对用户进行身份验证。

ASP.NET 检查 <authorization> 元素以确保用户在 <allow> 元素中。

授予用户访问 Default.aspx 的权限。

窗体身份验证的开发步骤

以下列表重点介绍实现窗体身份验证时必须执行的主要步骤:

1.

将 IIS 配置为使用匿名访问。

2.

将 ASP.NET 配置为使用窗体身份验证。

3.

创建登录 Web 窗体并检验所提供的凭证。

4.

从自定义数据存储中检索角色列表。

5.

创建窗体身份验证票证(在票证中存储角色)。

6.

创建一个 IPrincipal 对象。

7.

IPrincipal 对象放到当前 HTTP 上下文中。

8.

基于用户名/角色成员身份对用户授权。

将 IIS 配置为使用匿名访问

必须在 IIS 中将应用程序的虚拟目录配置为使用匿名访问。

将 IIS 配置为使用匿名访问的操作步骤

1.

启动 Internet 信息服务管理工具。

2.

选择应用程序的虚拟目录,右击,然后单击“属性”。

3.

单击“安全目录”。

4.

在“匿名访问”和“身份验证控制”组中,单击“编辑”。

5.

选择“匿名访问”。

将 ASP.NET 配置为使用窗体身份验证

下面显示一个配置示例。

<authentication mode="Forms">
  <forms name="MyAppFormsAuth" 
       loginUrl="login.aspx" 
       protection="Encryption"
       timeout="20" 
       path="/" >
  </forms>
</authentication>

创建登录 Web 窗体并验证提供的凭证

根据 SQL Server 数据库或 Active Directory 检验凭证。

更多信息

请参见“How To Use Forms Authentication with SQL Server 2000”。

请参见“How To Use Forms Authentication with Active Directory”。

从自定义数据存储中检索角色列表

从 SQL Server 数据库表中获取角色,或从在 Active Directory 内配置的组/分发列表中获取角色。详细信息请参考前面的资源。

创建窗体身份验证票证

在票证中存储检索到的角色。以下代码演示了此过程。

// This event handler executes when the user clicks the Logon button
// having supplied a set of credentials
private void Logon_Click(object sender, System.EventArgs e)
{
  // Validate credentials against either a SQL Server database
  // or Active Directory
  bool isAuthenticated = IsAuthenticated( txtUserName.Text, 
                                          txtPassword.Text );
  if (isAuthenticated == true )
  {
    // Retrieve the set of roles for this user from the SQL Server
    // database or Active Directory. The roles are returned as a
    // string that contains pipe separated role names
    // for example "Manager|Employee|Sales|"
    // This makes it easy to store them in the authentication ticket

    string roles = RetrieveRoles( txtUserName.Text, txtPassword.Text );

    // Create the authentication ticket and store the roles in the
    // custom UserData property of the authentication ticket
    FormsAuthenticationTicket authTicket = new 
       FormsAuthenticationTicket(
                    1,                          // version
                    txtUserName.Text,           // user name
                    DateTime.Now,               // creation
                    DateTime.Now.AddMinutes(20),// Expiration
                    false,                      // Persistent
                    roles );                    // User data
     // Encrypt the ticket.
     string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
     // Create a cookie and add the encrypted ticket to the 
     // cookie as data.
     HttpCookie authCookie = 
               new HttpCookie(FormsAuthentication.FormsCookieName,
                              encryptedTicket);

     // Add the cookie to the outgoing cookies collection. 
     Response.Cookies.Add(authCookie); 
     // Redirect the user to the originally requested page
     Response.Redirect( FormsAuthentication.GetRedirectUrl(
                        txtUserName.Text, 
                        false ));
  }
}

创建一个 IPrincipal 对象

在位于 Global.asax 的 Application_AuthenticationRequest 事件处理程序中创建 IPrincipal 对象。除非您需要基于角色的扩展功能,否则,请使用 GenericPrincipal 类。在本范例中创建一个实现 IPrincipal 的自定义类。

将 IPrincipal 对象放到当前的 HTTP 上下文中

GenericPrincipal 对象的创建过程如下所示。

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
  // Extract the forms authentication cookie
  string cookieName = FormsAuthentication.FormsCookieName;
  HttpCookie authCookie = Context.Request.Cookies[cookieName];
  if(null == authCookie)
  {
    // There is no authentication cookie.
    return;
  } 
  FormsAuthenticationTicket authTicket = null;
  try
  {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  }
  catch(Exception ex)
  {
    // Log exception details (omitted for simplicity)
    return;
  }
  if (null == authTicket)
  {
    // Cookie failed to decrypt.
    return; 
  }
  // When the ticket was created, the UserData property was assigned a
  // pipe delimited string of role names.
  string[] roles = authTicket.UserData.Split(new char[]{'|'});

  // Create an Identity object
  FormsIdentity id = new FormsIdentity( authTicket ); 
  // This principal will flow throughout the request.
  GenericPrincipal principal = new GenericPrincipal(id, roles);
  // Attach the new principal object to the current HttpContext object
  Context.User = principal;
}
  

基于用户名或角色成员身份对用户进行授权

使用声明性主体权限要求来限制对方法的访问。使用命令性主体权限要求和/或明确的角色检查 (IPrincipal.IsInRole) 在方法中执行细分的授权。

窗体实现原则

当使用 HTML 窗体捕获凭证时,请使用 SSL。

无论何时通过网络发送凭证或身份验证 Cookie,除了对登录页使用 SSL 外,还应该对其他页使用 SSL。这样,可以减轻与 Cookie 重播相关的威胁。

根据自定义数据存储验证用户的身份。请使用 SQL Server 或 Active Directory。

从自定义数据存储中检索角色列表,并在 FormsAuthenticationTicket 类的 UserData 属性中存储分隔的角色列表。这样不必为每个 Web 请求重复访问数据存储,从而提高了性能;而且还免去在身份验证 Cookie 中存储用户凭证的麻烦。

如果角色列表很大并且有超过 Cookie 大小限制的危险,请在 ASP.NET 缓存对象或数据库中存储角色的详细信息,并在每个后续请求中检索这些信息。

对于初始身份验证后的每个请求:

从位于 Application_AuthenticateRequest 事件处理程序的票证中检索角色。

创建一个 IPrincipal 对象并将其存储在 HTTP 上下文 (HttpContext.User) 中。.NET 框架还将其与当前 .NET 线程 (Thread.CurrentPrincipal) 关联起来。

除非您有特殊的原因需要创建自定义的 IPrincipal 实现,否则请使用 GenericPrincipal 类。

使用两种 Cookie:一种用于个性化,另一种用于安全的身份验证和授权。将个性化 Cookie 作为永久性的 Cookie(确保它不包含允许请求执行受限操作的信息;例如在站点的安全部分放置订单)。

对于每个 Web 应用程序,请使用单独的 Cookie 名称(使用 <forms> 元素的 Forms 属性)和路径。如果针对某个应用程序验证用户的身份,这可确保在使用同一 Web 服务器承载的第二个应用程序时,不会将这些用户作为已验证的用户处理。

确保在客户端浏览器中启用 Cookie。对于不需要 Cookie 的窗体身份验证方法,请参见本章后面的“无 Cookie 窗体身份验证”。

更多信息

请参见“How To Use Forms Authentication with SQL Server 2000”。

请参见“How To Use Forms Authentication with Active Directory”。

请参见“How To Create GenericPrincipal Objects with Forms Authentication”。

承载多个使用窗体身份验证的应用程序

如果在同一台 Web 服务器上承载多个使用窗体身份验证的 Web 应用程序,则在某个应用程序中已验证身份的用户可以请求另一个应用程序,而无需重定向到该应用程序的登录页。第二个应用程序中的 URL 授权规则可能会拒绝该用户的访问,而不会提供使用登录窗体提供登录凭证的机会。

这种情况只在以下情况下会发生:多个应用程序的 <forms> 元素的名称和路径属性相同,而且每个应用程序在 Web.config 中使用相同的 <machineKey> 元素。

更多信息

有关此问题的详细信息以及解决方法,请参见以下知识库文章:

Q313116“PRB:Forms Authentication Requests Are Not Directed to loginUrl Page

Q310415“PRB:Mobile Forms Authentication and Different Web Applications

无 Cookie 窗体身份验证

如果您需要无 Cookie 窗体身份验证解决方案,请考虑使用 Microsoft Mobile Internet Toolkit 所使用的方法。移动窗体身份验证建立在窗体身份验证之上,但使用查询字符串来传递身份验证票证,而不是使用 Cookie。

更多信息

有关移动窗体身份验证的详细信息,请参见 Microsoft 知识库文章 Q311568“INFO:How To Use Mobile Forms Authentication with Microsoft Mobile Internet Toolkit”。

Passport 身份验证

如果应用程序使用 Passport 帐户,而且您要在其他支持 Passport 的站点上实现单次登录解决方案,则应使用 Passport 身份验证。

当将 ASP.NET 配置为使用 Passport 身份验证时,就会提示用户登录并将该用户重定向到 Passport 站点。成功检验凭证之后,用户就会被重定向回您的站点。

将 ASP.NET 配置为使用 Passport 身份验证

要将 ASP.NET 配置为使用 Passport 身份验证,请使用以下 Web.config 设置。

<authentication mode="Passport">
  <passport redirectUrl="internal" />
</authentication>
<authorization>
  <deny users="?" />
  <allow users="*" />
</authorization>

将 Passport 标识映射到 Global.asax 中的角色

要将 Passport 标识映射到角色,请按如下所示在 Global.asax 中实现 PassportAuthentication_OnAuthentication 事件处理程序。

void PassportAuthentication_OnAuthenticate(Object sender, 
                                           PassportAuthenticationEventArgs e)
{
  if(e.Identity.Name == "0000000000000001")
  {
    string[] roles = new String[]{"Developer", "Admin", "Tester"};
    Context.User = new GenericPrincipal(e.Identity, roles);
  }
}
  

测试角色成员身份

以下代码片段显示了如何在 aspx 页中检索已验证身份的 Passport 标识和检查角色成员身份。

PassportIdentity passportId = Context.User.Identity as PassportIdentity;
if (null == passportId)
{
  Response.Write("Not a PassportIdentity");
  return;
}
Response.Write("IsInRole: Develeoper? " + Context.User.IsInRole("Developer"));
  

自定义身份验证

如果 .NET 框架提供的身份验证模块均不能满足您的确切身份验证需要,则可以使用自定义身份验证并实现您自己的身份验证机制。例如,您的公司可能已经制订了一个可由其他应用程序广泛使用的自定义身份验证策略。

要在 ASP.NET 中实现自定义身份验证,请执行下列操作:

按如下所示在 Web.config 中配置身份验证模式。这将通知 ASP.NET 不要调用它的任何内置的身份验证模块。

<authentication mode="None" />

创建实现 System.Web.IHttpModule 接口的类以创建自定义的 HTTP 模块。此模拟应该挂钩到 HttpApplication.AuthenticateRequest 事件中,并在要求身份验证时对每个应用程序请求提供要调用的委派。

身份验证模块必须:

从调用者获得凭证。

根据存储检验凭证。

创建一个 IPrincipal 对象并将其存储在 HttpContext.User 中。

创建并保护已验证身份的令牌,并将其发回给用户(通常在查询字符串、Cookie 或隐藏的窗体字段中)。

在后续请求中获得身份验证令牌,对它进行检验,然后重新分发。

更多信息

有关如何实现自定义 HTTP 模块的详细信息,请参见 Microsoft 知识库文章 Q307996“HOW TO:Create an ASP.NET HTTP Module Using Visual C# .NET”。

ASP.NET 的进程标识

使用权限最少的帐户运行 ASP.NET (具体来说就是 Aspnet_wp.exe 辅助进程)。

使用权限最少的帐户

使用权限最少的帐户可以减少与进程攻击相关的威胁。如果某个顽固的攻击者设法破坏了运行 Web 应用程序的 ASP.NET 进程,则这些应用程序可以轻易地继承和使用授予该进程帐户的特权和访问权限。配置为权限最少的帐户可以限制可能的潜在危害。

避免作为 SYSTEM 运行

不要使用高权限的 SYSTEM 帐户运行 ASP.NET,也不要授予 ASP.NET 进程帐户“充当操作系统的一部分”的权限。您可能很想使用其中的一种方法,通过代码调用 LogonUser API 以获取固定的标识(通常用于网络资源访问)。有关替代方法,请参见本章后面的“访问网络资源”。

不要以 SYSTEM 的身份运行或不授予“充当操作系统的一部分”权限的原因包括:

当系统遭到攻击时,它会大大增加攻击者所造成的危害,但不能增加防范攻击的能力。

它破坏了最少权限原则。ASPNET 已被明确配置为运行 ASP.NET Web 应用程序使用的权限最少的帐户。

更多信息

有关“充当操作系统的一部分”权限的详细信息,请参见 1999 年 8 月 Microsoft Systems Journal Security Briefs 专栏文章。

域控制器和 ASP.NET 进程帐户

一般情况下,不建议在域控制器上运行 Web 服务器,因为对服务器的攻击就是对域的攻击。正如 Microsoft 知识库文章 Q315158“BUG:ASP.NET Does Not Work with the Default ASPNET Account on a Domain Controller”中所概述的,如果需要在域控制器上运行 ASP.NET,则需要授予 ASP.NET 进程帐户相应的权限。

使用默认的 ASPNET 帐户

已将本地 ASPNET 帐户明确配置为使用尽可能最少的权限集运行 ASP.NET Web 应用程序。如果可能,尽量使用 ASPNET。

和 Machine.config 中的 <processModel> 元素所配置的一样,默认情况下,ASP.NET Web 应用程序使用此帐户运行。

<processModel userName="machine" password="AutoGenerate" />

machine 用户名表示 ASPNET 帐户。当安装 .NET 框架时,使用加密型密码创建该帐户。除了在安全帐户管理器 (SAM) 数据库中进行配置外,密码还存储在本地计算机上的本地系统授权 (LSA) 中。当系统启动 ASP.NET 辅助进程时,系统就会从 LSA 中检索密码。

如果应用程序访问网络资源,则 ASPNET 帐户必须能够由远程计算机验证身份。您有两种选择:

将 ASPNET 帐户的密码重置为某个已知值,然后在远程计算机上创建一个重复帐户(具有相同的名称和密码)。在以下情况下,此方法是惟一的选择:

Web 服务器和远程计算机位于单独的域中,并且域间没有信任关系。

Web 服务器和远程计算机由防火墙隔开,并且您不想打开支持 Windows 身份验证所需的端口。

如果您主要关心管理简便性问题,请使用权限最少的域帐户。

要避免必须手动更新和同步密码,可以使用权限最少的域帐户运行 ASP.NET。一定要完全锁定域帐户以减轻进程攻击的威胁。如果某个攻击者设法攻击了 ASP.NET 辅助进程,则他或她可以访问域资源,除非该帐户已完全锁定。

如果您使用本地帐户而且该帐户已被攻击,则惟一遭受攻击的计算机是您在上面创建重复帐户的计算机。如果您使用域帐户,则该帐户对域中的每台计算机都是可见的。但是,该帐户仍然需要拥有访问这些计算机的权限。

元素

Machine.config 文件中的 <processModel> 元素包含 userNamepassword 属性,这些属性指定应该使用哪些帐户来运行 ASP.NET 辅助进程 (Aspnet_wp.exe)。

与传统 ASP 应用程序的运行方式相比,ASP.NET 代码从不在 dllhost.exe 进程中运行或作为 IWAM_MACHINENAME 帐户运行,即使在 IIS 中将应用程序保护级别设置为“高(独立)”。

发送到 IIS 的 ASP.NET 请求被直接路由到 ASP.NET 辅助进程 (Aspnet_wp.exe)。ASP.NET ISAPI 扩展 Aspnet_isapi.dll 在 IIS (Inetinfo.exe) 进程地址空间中运行。(这是由 InProcessIsapiApps 元数据库项控制的;不要修改该元数据库项)。ISAPI 扩展负责将请求路由到 ASP.NET 辅助进程。然后,ASP.NET 应用程序在 ASP.NET 辅助进程中运行,其中应用程序域提供隔离边界。

在 IIS 6 中,您可以通过配置应用程序池来隔离 ASP.NET 应用程序,其中每个池都有自己的应用程序实例。

您可以使用多种方法来配置 <processModel> userName 属性。例如:

"machine"。辅助进程作为最少权限的默认 ASPNET 帐户运行。此帐户拥有网络访问权限,但不 能在网络上的任何计算机上验证该帐户的身份,因为该帐户是计算机的本地帐户,并且没有颁发机构担保此帐户。在网络上,此帐户表示为“MachineName\ASPNET”。

"system"。辅助进程作为本地 SYSTEM 帐户运行。此帐户在本地计算机上具有广泛的权限,而且还能够使用计算机的凭证访问网络。在网络上,此帐户表示为“DomainName\MachineName$”。

“特定验证信息”。当您为 userNamepassword 提供凭证时,请记住最少权限原则。如果您指定本地帐户,则在网络上不能对 Web 应用程序进行身份验证,除非您在远程计算机上创建重复帐户。如果您选择使用权限最少的域帐户,请确保它仅有权访问网络上所需的计算机。

存储加密的凭证

如果您使用自定义凭证,请使用 aspnet_setreg.exe 工具在注册表中存储加密的凭证。避免在 machine.config 中存储明文凭证。

有关这个工具的详细信息及下载,请参见 Microsoft 知识库文章 Q329290“HOWTO:Use the ASP.NET Utility to Encrypt Credentials and Session State Connection Strings”。

以下示例显示了这个工具使用前和使用后 userNamepassword 属性的格式。请注意该属性值如何指向安全的注册表项和包含加密凭证的命名值。

<!-- Before -->
<processModel userName="SomeCustomAccount"
              password="ClearTextPassword" . . ./>

<!-- After -->
<processModel
        userName="registry:HKLM\SOFTWARE\YourSecureApp\processModel\
                  ASPNET_SETREG,userName"
        password="registry:HKLM\SOFTWARE\YourSecureApp\processModel\
                  ASPNET_SETREG,password" . . ./>

更多信息

有关从 ASP.NET Web 应用程序访问网络资源的详细信息,请参见本章后面的“访问网络资源”。

有关如何创建用于运行 ASP.NET 的自定义帐户的详细信息,请参见“How To Create a Custom Account to Run ASP.NET”。

模拟

随时 FileAuthorizationModule 的引入以及网关守卫和信任边界的有效使用,现在看来,模拟技术在 ASP.NET 中是弊大于利。

模拟和本地资源

如果使用模拟并且从 Web 应用程序代码访问本地资源,则必须配置附加到每个受保护资源的 ACL,以包含一个至少授予已验证用户“读”访问权限的 ACE。

更好的方法是避免使用模拟,将权限授予 ASP.NET 进程帐户,并使用 URL 授权、文件授权以及基于角色的声明性和命令性检查组合。

模拟和远程资源

如果您使用模拟,然后从 Web 应用程序代码访问远程资源,则除非使用基本身份验证、窗体身份验证或 Kerberos 身份验证,否则访问将会失败。如果您使用 Kerberos 身份验证,则必须将用户帐户相应地配置为使用委派。在 Active Directory 中,必须将它们标记为“敏感帐户,不能被委派”。

更多信息

有关如何配置 Kerberos 委派的详细信息,请参见:

Intranet Security”一章中的“将原调用者传递到数据库”。

How To Implement Kerberos Delegation for Windows 2000”。

模拟和线程

如果某个正在模拟的线程创建了一个新线程,则该新线程将继承 ASP.NET 进程帐户的安全性上下文,而不是继承被模拟帐户的安全性上下文。

访问系统资源

默认情况下,ASP.NET 不执行模拟。因此,如果 Web 应用程序访问本地系统资源,则它使用与 Aspnet_wp.exe 辅助进程相关联的安全性上下文完成此任务。安全性上下文是由运行辅助进程使用的帐户决定的。

访问事件日志

权限最少的帐户拥有足够的权限,能够使用现有事件源将记录写入事件日志中。但是,它们没有足够的权限来创建新的事件源,这要求在下面的注册表配置单元底下设置一个新项。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\<log>

为了避免出现这种问题,请在安装时创建由应用程序使用的事件源(如果可以使用管理员权限的话)。一个好的办法是使用可由 Windows Installer(如果使用 .msi 部署的话)或 InstallUtil.exe 系统实用程序(如果没有使用 .msi 部署)实例化的 .NET 安装程序类。

如果在安装时无法创建事件源,则必须将权限添加到以下注册表项中,并授予某个被模拟帐户的 ASP.NET 进程帐户访问权限(如果应用程序使用模拟的话)。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog 

帐户必须拥有以下最少权限:

查询项值

设置项值

创建子项

枚举子项

通知

在将权限应用于注册表后,可以使用以下代码从 ASP.NET 写入应用程序事件日志:

string source = "Your Application Source";
string logToWriteTo = "Application";
string eventText = "Sample Event";

if (!EventLog.SourceExists(source))
{
  EventLog.CreateEventSource(source, logToWriteTo);
}
EventLog.WriteEntry(source, eventText, EventLogEntryType.Warning, 234);
  

访问注册表

应用程序访问的任何注册表项要求在 ACL 中使用 ACE,以便至少授予 ASP.NET 进程帐户“读”访问权限。

更多信息

有关安装程序类和InstallUtil.exe 实用工具的详细信息,请参见 MSDN 上的 .NET 框架 SDK 的“.NET 框架工具”部分。

访问 COM 对象

在传统 ASP 中,使用单线程单元 (STA) 线程池中的线程来处理请求。在 ASP.NET 中,使用多线程单元 (MTA) 线程池中的线程来处理请求。这会给调用单元模型对象的 ASP.NET Web 应用程序造成不利影响。

单元模型对象

当 ASP.NET Web 应用程序调用单元模型对象(如 Visual Basic 6 COM 对象)时,需要注意以下两个问题:

您必须用 AspCompat 指令标记 ASP.NET 页面(如下所示)。

<%@ Page Language="C#" AspCompat="True" %>

不要在特定的 Page 事件处理程序以外创建 COM 对象。始终在 Page 事件处理程序(例如, Page_LoadPage_Init)中创建 COM 对象。不要在页面的构造函数中创建 COM 对象。

需要 AspCompat 指令

默认情况下,ASP.NET 使用 MTA 线程处理请求。在从 ASP.NET 调用单元模型对象时,将会导致线程切换,这是因为 MTA 线程不能直接访问单元模型对象(COM 将使用 STA 线程)。

如果指定 AspCompat,则会由 STA 线程处理页面。这可以避免从 MTA 到 STA 的线程切换。如果 Web 应用程序使用模拟功能,从安全角度讲这是非常重要的,因为线程切换将会导致丢失模拟令牌。新线程将没有关联的模拟令牌。

ASP.NET Web 服务不支持 AspCompat 指令。这意味着,在从 Web 服务代码调用单元模型对象时,将会发生线程切换并且丢失线程模拟令牌。这通常导致出现“拒绝访问”异常错误。

更多信息

有关详细令牌,请参见以下知识库文章:

文章 Q303375“INFO:XML Web Services and Apartment Objects

文章 Q325791“PRB:Access Denied Error Message Occurs When You Impersonate an Account in ASP.NET and Then Call STA COM Components

有关如何确定当前执行代码的标识的详细信息,请参见“Troubleshooting”一章中的“确定标识”部分。

不要在特定 Page 事件以外创建 COM 对象

不要在特定 Page 事件处理程序以外创建 COM 对象。以下代码片段阐释了不要执行哪些操作。

<%@ Page Language="C#" AspCompat="True" %>
<script runat="server">
  // COM object created outside of Page events
  YourComObject obj = new apartmentObject();
  public void Page_Load()
  {
    obj.Foo()
  }
</script>

在使用单元模型对象时,一定要在特定 Page 事件(例如 Page_Load)中创建对象(如下所示)。

<%@ Page Language="C#" AspCompat="True" %>
<script runat="server">
public void Page_Load()
{
  YourComObject obj  = new apartmentObject();
  obj.Foo()
}
</script>

更多信息

有关详细信息,请参见 Microsoft 知识库文章 Q308095“PRB:Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Impacts Performance”。

COM+ 中的 C# 和 VB .NET 对象

Microsoft C#_ 开发工具和 Microsoft Visual Basic_ .NET 开发系统支持所有的线程模拟(自由线程、中性、两者和单元)。默认情况下,将 COM+ 中驻留的 C# 和 Visual Basic .NET 对象标记为“两者”。因此,当 ASP.NET 调用它们时,可以直接进行访问,而不会发生线程切换。

访问网络资源

应用程序可能需要访问网络资源。一定要能够标识以下内容:

应用程序需要访问的资源。

例如,文件共享上的文件、数据库、DCOM 服务器和 Active Directory 对象等等。

用来执行资源访问的标识。

如果应用程序访问远程资源,则远程计算机必须能够对此标识进行验证。

有关访问远程 SQL Server 数据库的信息,请参见“数据访问安全性”一章。

可以使用以下任一种方法,从 ASP.NET 应用程序中访问远程资源:

使用 ASP.NET 进程标识。

使用服务组件。

使用匿名 Internet 用户帐户(例如,IUSR_MACHINE)。

使用 LogonUser API 和模拟特定的 Windows 标识。

使用原调用者。

使用 ASP.NET 进程标识

如果没有将应用程序配置为使用模拟,在应用程序试图访问远程资源时,ASP.NET 进程标识就会提供默认标识。如果使用 ASP.NET 进程帐户访问远程资源,您有三种选择:

使用镜像帐户。

这是最简单的方法。您在远程计算机上使用匹配的用户名和密码创建一个本地帐户。您必须在用户管理器中将 ASPNET 帐户密码更改为已知值(始终使用强密码)。然后,必须在 Machine.config 中的“AutoGenerate”元素上明确地设置它,并替换现有的“AutoGenerate”值。避免使用明文凭证。如前面所述,使用 aspnet_setreg.exe 实用工具在注册表中存储加密凭证。

重要 如果将 ASPNET 密码更改为一个已知值,则 LSA 中的密码不再与 SAM 帐户密码匹配。如果需要恢复为“AutoGenerate”默认值,则需要执行以下任一操作:

运行 Aspnet_regiis.exe,将 ASP.NET 重置为其默认配置。有关详细信息,请参见 Microsoft 知识库文章 Q306005“HOWTO:Repair IIS Mapping After You Remove and Reinstall IIS”。

创建一个权限最少的自定义本地帐户以运行 ASP.NET,并在远程计算机上创建一个重复帐户。

使用一个权限最少的域帐户运行 ASP.NET。

假设客户端计算机和服务器计算机都位于同一个域或信任域内。

更多信息

有关配置 ASP.NET 进程帐户的详细信息,请参见“How To Create a Custom Account to Run ASP.NET”。

使用服务组件

可以使用配置为以固定标识运行的进程外服务组件来访问网络资源。图 6 显示了这种方式。

f08sn06

6. 使用进程外服务组件为网络资源访问提供固定标识

使用进程外服务组件(在 Enterprise Services 服务器应用程序中)具有以下优点:

在标识使用上具有很大灵活性。不是仅依赖于 ASP.NET 标识。

受信任的或具有更高权限的代码可以与主 Web 应用程序分开。

从安全角度来讲,由于增加了一个进程,所以提高了安全门槛。对于攻击者而言,穿过进程边界到达具有更高权限的进程要困难得多。

如果您需要使用 LogonUser API 调用进行手动模拟,则可以在与主 Web 应用程序分开的进程中执行此操作。

要调用 LogonUser,您必须授予 Enterprise Services 进程帐户“充当操作系统的一部分”的权限。可以通过提高与 Web 应用程序分开的进程的权限来减少安全隐患。

使用匿名 Internet 用户帐户

如果将 IIS 配置为使用匿名身份验证,则可以使用匿名 Internet 用户帐户访问网络资源。如果以下任一种情况属实,就会发生这种情况:

应用程序支持匿名访问。

应用程序使用窗体、Passport 或自定义身份验证(其中将 IIS 配置为使用匿名访问)。

使用匿名帐户访问远程资源

1.

将 IIS 配置为使用匿名身份验证。可以根据应用程序的身份验证要求,将 ASP.NET 身份验证模式设置为“Windows”、“窗体”、“Passport”或“无”。

2.

将 ASP.NET 配置为使用模拟。在 Web.config 中使用下列设置:

<identity impersonate="true" />

3.

将匿名帐户配置为权限最少的域帐户,

- 或者 -

在远程计算机上使用相同的用户名和密码复制匿名帐户。在不信任域之间进行调用时,或者通过没有打开支持集成 Windows 身份验证所需端口的防火墙进行调用时,必须使用此方法。

要支持这种方法,您还必须:

1.

使用 Internet 服务管理器清除匿名帐户的“允许 IIS 控制密码”复选框。

如果选择此选项,则使用指定匿名帐户创建的登录会话最终得到的是 NULL 网络凭证(因此不能用来访问网络资源)。如果不选择此选项,则登录会话是一个具有网络凭证的交互式登录会话。

2.

在用户管理器和 Internet 服务管理器中均设置帐户的凭证。

重要如果您模拟匿名帐户(例如,IUSR_MACHINE),则必须禁止该帐户访问资源(使用进行适当配置的 ACL)。对于应用程序需要访问的资源,必须(至少)授予匿名帐户“读”访问权限。应该拒绝匿名帐户访问所有其他资源。

承载多个 Web 应用程序

对于 Web 站点中的每一个虚拟根目录,可以使用一个单独的匿名 Internet 用户帐户。在承载环境中,这允许您分别授权、跟踪和审核来自不同 Web 应用程序的请求。 7 显示了这种方式。

f08sn07

7. 为每个应用程序模拟不同的匿名 Internet 用户帐户 (v-dir)

为特定的虚拟目录配置匿名 Internet 用户帐户

1.

“管理工具”程序组中启动“网络管理工具”。

2.

选择要配置的虚拟目录,右击,然后单击“属性”。

3.

单击“目录安全性”选项卡。

4.

在“匿名访问”和“身份控制”组中,单击“编辑”。

5.

选择“匿名访问”,然后单击“编辑”。

6.

键入在匿名用户连接到站点时希望 IIS 使用的帐户的用户名和密码。

7.

确保没有选中“允许 IIS 控制密码”。

使用 LogonUser 并模拟特定的 Windows 标识

可以使用以下方法模拟特定的标识:在 Web.config 中的 <identity> 元素上配置用户名和密码属性,或者在应用程序代码中调用 Win32_ LogonUser API。

重要 正如本章前面所提到的,当在 Windows 2000 服务器上使用 .NET Framework 1.0 时,不推荐使用 LogonUser 和固定的模拟标识,因为它强制给 ASP.NET 进程帐户授予“充当操作系统的一部分”权限。

Microsoft Windows .NET Server 2003 将取消这一限制。另外,在 Windows 2000 中,.NET Framework 1.1 版会为此方案提供一个增强功能。登录会由 IIS 进程执行,因此 ASP.NET 不需要“充当操作系统的一部分”权限。

使用原调用者

要使用原调用者的标识访问远程资源,您必须能够将调用者的安全性上下文从 Web 服务器委派到远程计算机。

可扩展性警告 如果使用原调用者的模拟标识访问应用程序的数据服务层,则会严重影响应用程序的可扩展性,这是因为数据库连接池的效率非常低。对于每个用户而言,数据库连接的安全性上下文是不同的。

以下身份验证方案支持委派:

Kerberos。有关详细信息,请参见“How To Implement Kerberos Delegation for Windows 2000”。

映射到 Windows 帐户的客户端证书。映射必须由 IIS 执行。

基本。基本身份验证支持远程资源访问,因为在 Web 服务器上以明文形式提供原调用者的凭证的。可以使用这些凭证响应来自远程计算机的身份验证质询。

必须将基本身份验证与交互式或批处理登录会话配合使用。可以在 IIS 元数据库中配置从基本身份验证产生的登录会话类型。有关详细信息,请参见 MSDN 上的 Platform SDK:Internet Information Services 5.1。

重要 在支持委派的方法中,基本身份验证是最不安全的一种方法。这是因为明文用户名和密码通过网络从浏览器传递到服务器,并且它们缓存在 Web 服务器的内存中。可以使用 IIS 在传递过程中保护凭证,但只要可能就应该避免在 Web 服务器上缓存明文凭证。

使用原调用者访问远程资源

1.

将 IIS 配置为使用集成 Windows (Kerberos)、证书(带 IIS 证书映射)或基本身份验证。

2.

将 ASP.NET 配置为使用 Windows 身份验证和模拟。

<authentication mode="Window" />
<identity impersonate="true" />

3.

如果使用 Kerberos 委派,请将 Active Directory 帐户配置为使用委派。

更多信息

有关配置 Kerberos 委派的详细信息,请参见“How To Implement Kerberos Delegation for Windows 2000”。

有关 IIS 证书映射的详细信息,请参见 http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/ad/windows2000/howto/mapcerts.asp

有关 ASP.NET 模拟的详细信息,请参见 MSDN 中的 .NET 框架开发人员指南

访问 UNC 文件共享上的文件

如果应用程序需要使用 ASP.NET 访问统一命名约定 (UNC) 共享上的文件,则一定要添加共享文件夹的 NTFS 权限。您还需要设置共享的权限,以便授予 ASP.NET 进程帐户或模拟的标识至少“读”访问权限(如果将应用程序配置为使用模拟的话)。

访问非 Windows 网络资源

如果应用程序需要访问非 Windows 资源(例如位于非 Windows 平台上的数据库或大型机应用程序),则需要考虑以下问题:

与资源相关的网关守卫和信任边界是什么?

身份验证需要哪些凭证?

资源是否需要知道原调用者的标识,或者它是否信任调用应用程序(使用固定标识或服务标识)?

与建立连接相关的性能开销有多大?如果开销很大,则可能需要实现连接池;例如,使用 Enterprise Services 的对象池功能。

如果资源需要能够对原调用者进行身份验证(并且不能选用 Windows 身份验证),则可以选择以下方法:

使用(方法调用)参数传递凭证。

在连接字符串中传递凭证。使用 SSL 或 IPSec 保护通过网络传递的明文凭证。

在应用程序中安全地存储凭证,例如使用 DPAPI。有关安全地存储数据库连接字符串的详细信息,请参见“数据访问安全性”一章中的“安全存储数据库连接字符串”。

使用两个平台都能访问的集中数据存储进行身份验证;例如,LDAP 目录。

安全通信

使用 SSL 保护浏览器和 Web 服务器之间通信链路的安全。SSL 提供消息机密性和消息完整性。使用 SSL 和/或 IPSec 提供从 Web 服务器到应用程序服务器或数据库服务器的安全通道。

更多信息

有关安全通信的详细信息,请参见“Secure Communication”一章。

存储机密

Web 应用程序通常需要存储机密。需要妥善保管这些机密,以防止不道德的管理员和有恶意的 Web 用户进行访问,例如:

不道德的管理员。不应该授予不道德的管理员和其他用户查看特权信息的权限。例如,不应该授予 Web 服务器管理员读取网络中 SQL Server 计算机上的 SQL Server 登录帐户密码的权限。

恶意的 Web 用户。即使可以使用某些组件(例如 FileAuthorizationModule)禁止用户访问特权文件(如果攻击者确实获得访问配置文件的权限),文件中的机密也不应该以纯文本形式存储。

机密的典型示例包括:

SQL 连接字符串。一个常见的错误是以纯文本形式存储用户名和密码。建立使用 Windows 身份验证而不是 SQL 身份验证。如果不能使用 Windows 身份验证,请参见“数据访问安全性”一章中的以下部分,它们介绍了其他的安全方案:

“安全地存储数据库连接”

“安全通信”

SQL 应用程序角色使用的凭证。必须使用需要角色名及相关密码的存储过程激活 SQL 应用程序角色。有关详细信息,请参见“数据访问安全性”一章中的“授权”。

Web.config 中的固定标识。例如:

<identity impersonate="true" userName="bob" password="inClearText"/>

aspnet_setreg.exe 实用工具允许您将明文凭证替换为指向包含加密凭证的安全注册表项的指针。

Machine.config 中的进程标识。例如:

<process userName="cUsTuMUzerName" password="kUsTumPazzWerD" >

按照 <identity> 元素,您必须使用 aspnet_setreg.exe 将加密凭证存储在注册表中。

用于安全地存储数据的密钥。无法在软件中安全地存储密钥。但是,可以使用某些任务降低风险。例如,创建一个自定义的配置节处理程序,它使用不对称加密对会话密钥进行加密。然后,可以将会话密钥存储在配置文件中。

SQL Server 会话状态。要使用 SQL 服务器管理 ASP.NET Web 应用程序会话状态,请使用以下 Web.config 设置。

<sessionState … stateConnectionString="tcpip=127.0.0.1:42424"
                sqlConnectionString="data source=127.0.0.1;
                user id=UserName;password=MyPassword" />

aspnet_setreg.exe 也支持 <sessionState> 元素中的 stateConnectionStringsqlConnectionString 属性,该元素允许您将这些值以加密格式存储到注册表中。

用于根据数据库进行窗体身份验证的密码

如果应用程序根据数据库检验身份验证凭证,请不要将密码存储在数据库中。使用带有 Salt 值的密码哈希值并对哈希值进行比较。

有关更多信息,请参见“数据访问安全性”一章中的“对数据库进行用户身份验证”。

在 ASP.NET 中存储机密的选项

.NET Web 应用程序开发人员可以使用多种方法来存储机密。它们是:

“.NET安全类”。.NET 框架包含可用于加密和解密的类。这些方法要求安全地存储加密密钥。

“数据保护API” (DPAPI)。DPAPI 是一对 Win32 API,它使用从用户密码派生的密钥对数据进行加密和解密。在使用 DPAPI 时,您并不需要进行密钥管理。操作系统将对作为用户密码的密钥进行管理。

“COM+构造字符串”。如果应用程序使用服务组件,则可以在对象构造字符串中存储机密。该字符串以明文形式存储在 COM+ 目录中。

CAPICOM。这是一个 Microsoft COM 对象,它提供对基础加密 API 基于 COM 的访问。

Crypto API。这些 API 是执行加密和解密的低级 Win32 API。

更多信息

有关详细信息,请参见 MSDN 上 Platform SDK 中的加密技术、CryptoAPI 和 CAPICOM 条目。

考虑将机密存储在单独逻辑卷上的文件中

考虑将 Web 应用程序目录安装到操作系统所在卷以外的逻辑卷上(例如 E: 而不是 C:)。这意味着 Machine.config(位于 C:\WINNT\Microsoft.NET 下)和其他可能包含机密的文件(例如通用数据链接 (UDL) 文件)都位于 Web 应用程序目录以外的逻辑卷上。

此方法的基本原理是防止出现可能的文件规范化和目录遍历错误,因为:

文件规范化错误可能会公开 Web 应用程序文件夹中的文件。

文件规范化例程返回文件路径的规范形式。这通常是绝对路径名,其中已完全解析所有相对引用和对当前目录的引用。

目录遍历错误可能会公开同一逻辑卷上其他文件夹中的文件。

公开其他逻辑卷上文件的上述类型错误尚未发布。

保护会话和视图状态

Web 应用程序必须管理各种类型的状态,其中包括视图状态和会话状态。本节讨论 ASP.NET Web 应用程序的安全状态管理。

保护视图状态

如果 ASP.NET Web 应用程序使用视图状态:

按如下所示将 enableViewStateMac 设置为 true,以确保视图状态的完整性(确保在传递过程中没有对它进行修改)。这样,在从客户端发回页面时,ASP.NET 就会在该页面的视图状态上生成消息身份验证代码 (MAC)。

<% @ Page enableViewStateMac=true >
  

配置 Machine.config 中 <machineKey> 元素的 validation 属性,指定数据检验所使用的加密类型。请考虑 validation 属性的以下几方面的问题:

安全哈希算法 1 (SHA1) 生成的哈希大小比消息摘要 5 (MD5) 大,因而可以认为它更安全。但是,在传递过程中或在客户端可能会解码使用 SHA1 或 MD5 保护的视图状态,并可能以纯文本形式进行查看。

使用三重数据加密标准 (3DES) 检测视图状态中的变化,并且还可以在传递过程中对视图状态进行加密。在处于这种状态时,即使视图状态被解码,也不能以纯文本形式进行查看。

保护 Cookies

在传递过程中,应该使用 SSL 保护包含身份验证或授权数据或其他机密数据的 Cookie。对于窗体身份验证,可以使用 FormsAuthentication.Encrypt 方法加密以 Cookie 形式在客户端和服务器之间传递的身份验证票证。

保护 SQL 会话状态

默认(进程内) ASP.NET 会话状态处理程序会受到某些限制。例如,它不能在网络场中的其他计算机上运行。为了克服此限制,ASP.NET 允许在 SQL Server 数据库中存储会话状态。

可以在 Machine.config 或 Web.config 中配置 SQL 会话状态。machine.config 的默认设置如下所示。

<sessionState mode="InProc" 
              stateConnectionString="tcpip=127.0.0.1:42424" 
              stateNetworkTimeout="10"
              sqlConnectionString="data source=127.0.0.1;user id=sa;password="
              cookieless="false" timeout="20"/>

默认情况下, SQL 脚本 InstallSqlState.sql (用于生成 SQL 会话状态使用的数据库)安装在以下位置:

C:\WINNT\Microsoft.NET\Framework\v1.0.3705

在使用 SQL 会话状态时,需要考虑以下两个问题。

必须保护数据库连接字符串的安全。

在网络上传递时,必须保护会话状态的安全。

保护数据库连接字符串

如果使用 SQL 身份验证连接到服务器,则连接字符串在包含用户名和密码的 sqlConnectionString 属性中指定。使用 aspnet_setreg.exe 实用工具在注册表中存储加密的连接字符串。以下示例显示了使用 aspnet_setreg.exe 前后的 <sessionState> 元素。

<!-- Before -->
<sessionState 
    mode="SQLServer", 
    sqlConnectionString="data source=Server;user id=userID;password=pwd" . . . />
<!-- After -->
<sessionState mode="SQLServer"
              sqlConnectionString="registry:HKLM\SOFTWARE\YourSecureApp\
              sessionState\ASPNET_SETREG,sqlConnectionString" />

如果您使用 ASP.NET 状态服务,也可以使用 aspnet_setreg.exe 来加密 stateConnectionString 属性。

如果可能,应该对 SQL Server 状态数据库使用 Windows 身份验证。这将带来其他一些优点:连接字符串不包含凭证,凭证不通常网络传递到数据库服务器。

要使用 Windows 身份验证,可以使用 ASP.NET 进程标识(通常是 ASPNET)

1.

在数据库服务器上创建一个重复的帐户(使用相同的名称和密码)。

2.

为该帐户创建 SQL 登录。

3.

ASPState 数据库中创建一个数据库用户,并将 SQL 登录映射到该新用户。

ASPState 数据库是由 InstallSQLState.sql 脚本创建的。

4.

创建一个用户定义的数据库角色,并将数据库用户添加到该角色。

5.

在数据库中为该数据库角色配置权限。

然后,可以更改连接字符串以使用受信任的连接(如下所示):

sqlConnectionString="server=127.0.0.1;
                     database=StateDatabase;
                     Integrated Security=SSPI;"

在网络上保护会话状态

在通过网络将会话状态传递到 SQL Server 数据库时,可能需要对会话状态进行保护。这取决于承载 Web 服务器和数据服务器的网络的安全性。如果已在受信任环境中对数据库进行物理保护,则可能不必采取这一额外的安全措施。

可以使用 IPSec 保护 Web 服务器和 SQL Server 之间的所有 IP 通信,或者使用 SSL 保护到 SQL Server 的链路。通过使用此方法,您可以选择只加密用于会话状态的连接,而不是在计算机之间进行的所有通信。

更多信息

有关如何设置 SQL 会话状态的详细信息,请参见 Microsoft 知识库文章 Q317604“HOW TO:Configure SQL Server to Store ASP.NET Session State”。

有关对 SQL Server 使用 SSL 的详细信息,请参见“How To Use SSL to Secure Communication with SQL Server 2000”。

有关使用 IPSec 的详细信息,请参见“How To Use IPSec to Provide Secure Communication Between Two Servers”。

网络场注意事项

在网络场方案中,不能保证来自同一个客户端的后续请求由同一个 Web 服务器提供服务。对于状态管理和任何取决于 Machine.config 中 <machineKey> 元素所保存的属性的加密而言,这会产生不利影响。

会话状态

默认 ASP.NET 进程内会话状态处理(它镜像以前的 ASP 功能)产生服务器关系,并且不能在网络场方案中使用。对于网络场部署,必须在进程外将会话状态存储到 ASP.NET 状态服务或 SQL Server 数据库中(如前所述)。

不能依赖应用程序状态来保存网络场(将 Web 应用程序配置为在多台服务器上运行)或网络园(将 Web 应用程序配置为在多个处理器上运行)方案中的全局计数器或惟一值,因为在进程或计算机之间不能共享应用程序状态。

DPAPI

DPAPI 能够与机器存储或用户存储(需要一个已加载的用户配置文件)配合使用。如果您将 DPAPI 和机器存储一起使用,那么加密字符串是给定计算机所特有的,因此您必须在每台计算机上生成加密数据。不要在网络场或群集中的计算机之间复制加密数据。

如果将 DPAPI 和用户存储一起使用,则可以用一个漫游的用户配置文件在任何一台计算机上解密数据。

更多信息

有关 DPAPI 的详细信息,请参见“数据访问安全性”一章。

在网络场中使用窗体身份验证

如果使用窗体身份验证,则网络场中的所有服务器必须共享一个通用机密密钥,此密钥用于身份验证票证的加密、解密和验证。

机密密钥保存位于 Machine.config 的 <machineKey> 元素中。默认设置如下所示。

<machineKey validationKey="AutoGenerate" 
            decryptionKey="AutoGenerate" 
            validation="SHA1"/> 

此设置导致每台机器生成一个不同的检验和解密密钥。必须更改 <machineKey> 元素,并将通用密钥值放在网络场中的所有服务器上。

元素

可以使用 Machine.config 中的 <machineKey> 元素,配置用于加密和解密窗体身份验证 Cookie 数据和视图状态的密钥。

在调用 FormsAuthentication.EncryptFormsAuthentication.Decrypt 方法以及创建或检索视图状态时,将参考 <machineKey> 元素中的值。

<machineKey validationKey="autogenerate|value"
            decryptionKey="autogenerate|value"
            validation="SHA1|MD5|3DES" />

validationKey 属性

validationKey 属性值用于创建和检验视图状态和窗体身份验证票证的 MAC 代码。此检验属性表明在执行 MAC 生成时使用哪种算法。请注意以下方面:

在使用窗体身份验证时,此密钥与 <forms> protection 属性配合使用。如果将保护属性设置为 Validation,然后调用 FormsAuthentication.Encrypt 方法,则使用票证值和 validationKey 来计算附加到 Cookie 中的 MAC。在调用 FormsAuthentication.Decrypt 方法时,就会计算 MAC 并将它与附加到票证上的 MAC 进行比较。

在使用视图状态时,可以使用控件的视图状态和 validationKey 来计算附加到视图状态上的 MAC。在将视图状态从客户端发回时,应重新计算 MAC 并将它与附加到视图状态上的 MAC 进行比较。

decryptionKey 属性

decryptionKey 属性值用于加密和解密窗体身份验证票证和视图状态。可以使用 DES 或 Triple DES (3DES) 算法。具体的算法取决于服务器上是否安装了 Windows 2000 高度加密包。如果安装了该程序包,则使用 3DES,否则使用 DES。请注意以下方面:

在使用窗体身份验证时,密钥与 <forms> protection 属性配合使用。如果将 protection 属性设置为 Encryption,并且调用了 FormsAuthentication.EncryptDecrypt 方法,则使用指定的 decryptionKey 值加密或解密票证值。

通过使用视图状态,在将控件的视图状态值发送到客户端时,使用 decryptionKey 值对它进行加密;并在客户端将数据发回服务器时对它进行解密。

Validation 属性

此属性规定检验、加密和解密时使用哪种算法。它可以采用 SHA1、MD5 或 3DES 值。以下是这些值的描述:

SHA1。如果设置为 SHA1,则实际使用 HMACSHA1 算法。它生成 160 位(20 个字节)的输入哈希值或摘要。HMACSHA1 是一种加密哈希算法。此算法的输入密钥是由 validationKey 属性指定的。

SHA1 由于比其他算法具有更大的摘要,因此成为常用的算法。

MD5。它使用 MD5 算法生成 20 个字节的哈希值。

3DES。它使用 Triple DES (3DES) 算法加密数据。

在将验证属性设置为 3DES 时,窗体身份验证实际上并不使用它,而是使用 SHA1。

更多信息

有关如何创建适于放在 Machine.config 中的密钥的信息,请参见 Microsoft 知识库文章 Q312906“HOW TO:Create Keys by using Visual C# .NET for Use in Forms Authentication”。

有关 Windows 2000 高度加密包的详细信息,请参见 http://www.microsoft.com/windows2000/downloads/recommended/encryption/

小结

本章介绍了各种保护 ASP.NET Web 应用程序的技术和方法。本章提供的大多数指南和建议同样适用于开发 ASP.NET Web 服务和由 ASP.NET 驻留的 .NET Remoting 对象。概括如下:

如果应用程序使用窗体身份验证,而且在用户身份验证中需要考虑性能问题,则检索角色列表并将其存储在身份验证票证中。

如果使用窗体身份验证,则始终给每个请求创建一个主体并将其存储在上下文中。

如果角色太多而无法存储在身份验证 Cookie 中,则使用全局应用程序缓存来存储角色。

不要创建权限最少的自定义帐户来运行 ASP.NET。而是应该更改 ASPNET 帐户密码,并在应用程序需要访问的任何远程 Windows 服务上创建重复帐户。

如果必须创建自定义帐户以运行 ASP.NET,请使用权限最少的用户。例如:

如果主要考虑管理问题,请使用权限最少的域帐户。

如果使用本地帐户,则必须在 Web 应用程序需要访问的任何远程计算机上创建重复帐户;如果应用程序需要访问非信任域中的资源或者防火墙禁止 Windows 身份验证,则必须使用本地帐户。

不要使用本地 SYSTEM 帐户来运行 ASP.NET。

不要授予 ASPNET 帐户“充当操作系统的一部分”权限。

在以下情况中使用 SSL:

在浏览器和 Web 服务器之间传送安全敏感信息时。

使用基本身份验证(以保护凭证)时。

使用窗体身份验证进行身份验证(与个性化相对)时。

避免以纯文本形式存储机密。

不要在 machine.config 和 Web.config 中存储纯文本凭证。对于 <identity>, <processModel> 和 <sessionState> 元素,使用 aspnet_setreg.exe 实用工具在注册表中存储加密凭证。

本文地址:http://com.8s8s.com/it/it43836.htm