身份验证和授权
![](https://i-blog.csdnimg.cn/blog_migrate/78954a80378de8161be0809b1d3d4759.png)
Microsoft Corporation
本章内容
为分布式 Web 应用程序设计身份验证和授权机制是一项具有挑战性的任务,您必须做出的选择中有许多几乎会对您开发的应用程序的每个组件产生影响。采用合适的身份验证和授权设计方案有助于降低许多主要的安全风险。在应用程序开发的早期阶段实现这样的设计比尝试改进现有的或已部分构建的应用程序解决方案来得轻松许多。
本章描述了在开发分布式 ASP.NET Web 应用程序时可用的身份验证和授权机制。同时描述一个您可采用,有助于为您的应用程序选择最合适的身份验证和授权机制的过程。
目标
利用本章来:
• | 了解通过多个应用程序层的流身份的各种选项。 |
• | 确定在分布式 Web 应用程序中使用的合适的身份验证和授权机制。 |
• | 比较和对比在分布式 .NET Web 应用程序中用于身份验证和授权的“模拟/委派”(也就是“原调用者”)和“受信任子系统”模式之间的异同。 |
• | 比较和对比基于角色和基于资源的授权方式。 |
适用于:
本章内容适用于以下产品和技术:
• | Microsoft Windows XP 或 Windows 2000 Server (带 service pack 3),以及更高版本的操作系统。 |
• | Microsoft Internet Information Services (IIS) 5.0 和更高版本 |
• | Microsoft Active Directory 目录服务 |
• | .NET Framework 1.0 版(带 service pack 2)和更高版本 |
• | SQL Server™ 2000(带 service pack 2)和更高版本 |
如何使用本章
本章描述为分布式 Web 应用程序确定合适的身份验证和授权机制的过程。越早考虑应用程序的身份验证和授权要求,这些机制就能越早实现,应用程序也可能越安全。要想从本章获得最大价值,您应该:
• | 阅读本章中的“构建安全的 ASP.NET 应用程序介绍”。它定义了与分布式 Web 应用程序相关的“身份验证”和“授权”术语。 | ||||||||||||||||||
• | 阅读本章中的“用于 ASP.NET 应用程序的安全模式”。它概述了创建分布式 ASP.NET Web 应用程序所使用的体系结构和技术。它介绍本章深入讨论的身份验证和授权机制,并定义授权主题的核心内容—网关和网关守卫的概念。 | ||||||||||||||||||
• | 阅读以下章节,它们论证本章所讨论的身份验证和授权技术的实现:
|
![*](http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif)
本页内容
![]() | 准备工作 |
![]() | 设计身份验证和授权策略 |
![]() | 授权方法 |
![]() | 传递身份 |
![]() | 基于角色授权 |
![]() | 选择身份验证机制 |
![]() | 小结 |
准备工作
为分布式 Web 应用程序设计一种身份验证和授权策略是一项具有挑战性的任务。 令人欣慰的是,在应用程序开发的早期阶段,正确设计身份验证和授权将有助于降低许多安全方面的主要风险。
本章将帮助您为应用程序设计适当的授权策略,也将帮助您解答下列关键问题:
• | 应该在什么情况下执行授权,使用什么机制? |
• | 应该使用什么身份验证机制? |
• | 应该用 Active Directory 目录服务来进行身份验证,还是应该对照自定义数据存储来验证凭证? |
• | 使用异类和同类平台分别意味着什么?在设计上有哪些需要注意的地方? |
• | 在应用程序中应该如何表示没有使用 Windows 操作系统的用户? |
• | 应该如何在应用程序的各层之间传递用户身份? 在什么情况下应该使用操作系统级模拟/委派? |
当您考虑授权时,也必须考虑身份验证。两个过程是同时进行的,这有两方面的原因:
• | 首先,任何有意义的授权策略都要求已验证身份的用户。 |
• | 其次,验证用户身份的方式(具体说,就是如何在应用程序中表示已通过验证的用户身份)将决定您可支配的网关守卫。 某某些网关守卫,(如, ASP.NET 文件授权、Enterprise Services (COM+) 角色和 Windows ACL) 都需要一个通过身份验证的 Windows 身份(以 WindowsIdentity 对象的形式存在,它封装了一个定义调用者安全上下文的 Windows 访问令牌。) 而其他网关守卫,(如 ASP.NET URL 授权和 .NET 角色)则没有这一要求。它们只要求身份通过验证即可,并不需要一定是由 Windows 访问令牌来表示。 |
设计身份验证和授权策略
以下步骤确定了帮助您为应用程序制定身份验证和授权策略的过程:
• | 标识资源。 |
• | 选择授权策略。 |
• | 选择用于资源访问的身份。 |
• | 考虑身份传递。 |
• | 选择身份验证方法。 |
• | 决定如何传递身份。 |
确定资源
确定应用程序需要向客户端公开的资源。典型资源包括:
• | Web Server 资源,例如 Web 页面、Web 服务、静态资源(HTML 页面和图像)。 |
• | 数据库资源,例如每用户数据或应用程序范围的数据。 |
• | 网络资源,例如远程文件系统资源和来自目录存储(如 Active Directory)的数据。 |
还必须确定应用程序需要访问的系统资源。这些资源与向客户端公开的资源相反,是不公开的。 它们包括注册表、事件日志和配置文件。
选择授权策略
有两种基本的授权策略:
• | 基于角色。对操作(通常是方法)的访问是基于调用者的角色成员保护的。 使用角色将应用程序的用户群分成在应用程序内共享相同安全特权的用户组;例如“高级经理”、“经理”和“职员”。用户被映射到角色,如果用户有权所请求的操作,则应用程序就会使用固定的身份访问资源。这些身份受各自的资源管理器(例如数据库、文件系统等)所信任。 |
• | 基于资源。使用 Windows ACL 分别保护各个资源。应用程序在调用者访问资源前先对其进行模拟,这样使操作系统可以执行标准的访问检查。所有资源访问都是通过原调用者的安全上下文执行的。 此模拟方法严重影响应用程序的可扩展性,因为这意味着在应用程序的中间层无法有效地使用连接池。 |
在绝大多数必须进行扩展的 .NET Web 应用程序中,基于角色授权方法是最好的选择。而某些规模较小的 Intranet 应用程序则从各种资源(如文件)中提取单个用户信息,当各个用户访问这些资源时,这些资源是通过 Windows ACL 加以保护的,因此更适合采用基于资源的授权方式。
在进行基于角色授权时,推荐使用和常见的做法是:
• | 在前端 Web 应用程序中验证用户身份。 |
• | 将用户映射到角色。 |
• | 基于角色成员授权对操作(而不是直接对资源)进行访问。 |
• | 使用固定的服务身份访问必要的后端资源(用来支持所请求的和授权的操作)。后端资源管理器(例如,数据库) 信任 应用程序可以授权调用者,并且愿意授予权限给受信任的服务身份。 例如,数据库管理员可能只授予访问特定人力资源应用程序(而不是个别用户)的访问权限。 注 应用程序级别的基于角色授权方式仍然需要使用基于资源的授权来保护系统级资源,例如配置文件、注册表项等。 |
更多信息
• | 有关这两种截然不同的授权方式的更多信息,请参考本章后面的“授权方式”。 |
• | 有关基于角色授权和各种可以使用的角色类型的更多信息,请参考本章后面的“基于角色授权”。 |
选择用于资源访问的身份
请回答这样的问题:“谁将访问资源?”
选择用来在应用程序各个层进行资源访问的身份。这些资源可以由基于 Web 的应用程序来访问,还可以由 Web 服务、Enterprise Service 和 .NET 远程处理组件访问。一般来讲,用于资源访问的身份可以是以下几类:
• | 原调用者的身份。它采用一种模拟/委派模式,即可以获得原调用方身份,然后将此身份在系统的每一层之间传递。委派因素是用于确定身份验证机制的重要标准。 | ||||
• | 进程身份。这是默认情况(没有具体的模拟)。使用当前进程身份可以访问本地资源并进行下游调用。这一方法是否可靠取决于所跨越的界限,因为进程身份必须被目标系统识别。 这意味着要用以下方式之一进行调用:
| ||||
• | 服务帐户。本方法使用一个(固定的)服务帐户。例如:
| ||||
• | 自定义身份。当没有可用的 Windows 帐户时,您可以构造自己的身份(使用 IPrincipal 和 IIdentity 模拟),它将包含您指定的安全上下文的具体内容。例如,它可以包含角色列表、惟一标识符或任何其他类型的自定义信息。 通过用 IPrincipal 和 IIdentity 类型实现自定义身份并将它们放置在当前 Web 上下文(使用 HttpContext.User),您可以直接从内置的网关守卫(如 .NET 角色和 PrincipalPermission 命令)中获益。 |
考虑身份传递
为了支持每用户授权、审核和每用户数据检索,您可能需要在不同的应用程序层之间和不同计算机之间传递调用者身份。例如,如果某个后端资源管理器需要执行每用户授权,调用者身份就必须传递给该资源管理器。
您要根据系统的资源管理器授权要求和审核要求来确定需要在应用程序中传递的身份。
选择身份验证方式
影响身份验证方式选择有两个关键因素:第一,也是最重要的因此是,应用程序的用户群的特点(他们使用哪一类浏览器以及他们是否有 Windows 帐户);第二是,应用程序的模拟/委派和审核要求。
更多信息
有关帮助您为应用程序选择身份验证机制的更多具体考虑事项,请参考本章后面的“选择身份验证机制”。
决定如何传递身份
您可以在应用程序级传递身份(以提供安全上下文),也可以在操作系统级传递身份和安全上下文。
要在应用程序级传递身份,请使用方法和存储过程参数。应用程序身份传递支持:
• | 使用受信任的查询参数检索每用户数据 SELECT x,y FROM SomeTable WHERE username="bob" |
• | 在任何应用程序层中自定义审核 |
操作系统身份传递支持:
• | 平台级审核(例如,Windows 审核和 SQL Server 审核) |
• | 基于 Windows 身份的每用户授权 |
为了在操作系统级传递身份,您可以使用模拟/委派模式。在有些环境下,可以使用 Kerberos 委派,而在其他环境下(多半是不支持 Kerberos 的环境),您可能需要使用其他方法,例如使用基本身份验证。在基本身份验证下,用户凭证可由服务器应用程序使用,还可以用于访问下游网络资源。
更多信息
有关身份传递以及如何用网络凭证获得模拟令牌(即支持委派)的更多信息,请参考本章后面的“传递身份”。
授权方法
有两种基本的授权方法:
• | 基于角色。用户被划分为由应用程序定义的逻辑角色。在应用程序中,某一特定角色的成员将共享相同的特权。对操作的访问(通常由方法调用表示)是根据调用者的角色成员授权的。 可以用固定身份(例如 Web 应用程序身份或 Web 服务进程身份)访问资源。资源管理器信任应用程序可以正确授权用户,并且它们将权限授予 受信任 的身份。 |
• | 基于资源。各个资源是通过 Windows ACL 保护的。ACL 将决定哪些用户允许访问资源,还决定允许每个用户执行哪类操作(读、写、删除等)。 可以使用原调用者的身份(使用模拟)访问资源。 |
基于角色授权
在基于角色(或操作)的安全方法中,对操作(而非后端资源)的访问是根据调用者的角色成员进行授权的。(在应用程序设计时分析和定义的)角色被用作逻辑容器,它们将在应用程序中共享相同安全特权(或功能)的用户组合起来。用户被映射到应用程序中的角色,而角色成员用来控制对由应用程序公开的特定操作(方法)的访问权。
在应用程序的什么位置映射角色是设计中需要考虑的一个关键因素;例如:
• | 在一种极端情况下,可以在后端资源管理器(例如数据库)中映射角色。它要求原调用者的安全上下文通过应用程序的各层传递到后端数据库。 |
• | 另一种极端情况是在前端 Web 应用程序中映射角色。在这种方法中,下游资源管理器是通过由每个资源管理器授权并受其信任的固定身份访问的。 |
• | 第三种情况是在前端和后端层之间的某个位置进行角色映射;例如,在中间层 Enterprise Services 应用程序中。 |
在多层 Web 应用程序中,使用受信任的身份访问后端资源管理器为应用程序提供更大的可扩展空间(这归功于连接池)。另外,使用受信任身份减少了在操作系统级传递原调用者安全上下文的需要,而这是很难以实现的(即使在某些情况下并非不可能实现)。
基于资源的授权
基于资源的授权方法依赖于 Windows ACL 和操作系统基本的访问控制机制。应用程序模拟调用者,将执行访问检查的任务留给与特定资源管理器(文件系统、数据库等)关联的操作系统。
这种方法最适合于这样的应用程序,即用它们来访问可通过 Windows ACL 单独保护的资源,如文件资源。FTP 应用程序或简单的数据驱动 Web 应用程序就属于这类应用程序。如果被请求资源中的数据需要从多个不同来源(例如,多个数据库、数据库表、外部应用程序或 Web 服务)获得并合并,则这种方法就力不从心了。
基于资源的方法也依赖于传递到应用程序后端资源管理器的原调用者安全上下文。这种方法配置复杂,并大大降低了多层应用程序增加受访的能力,因为使用这种方法,您就无法在应用程序中间层有效运用集合功能(例如,数据库连接集合)。
资源访问模式
通过研究 .NET Web 应用程序(以及一般情况下分布式多层应用程序)最常用的两种资源访问安全模式,我们可以看到两种截然不同的授权方法。它们是:
• | 受信任的子系统模式 |
• | 模拟/委派模式 |
两种模式在安全和可扩展性方面都各有优缺点。以下部分将介绍这些模式。
受信任的子系统模式
在这种模式中,中间层服务使用固定身份访问下游服务和资源。原调用者安全上下文不在操作系统级通过服务传递,但应用程序可以选择在应用程序级传递原调用者身份。可能需要这样做才能支持后端审核要求,或者才能支持每用户数据访问和授权。
该模式的名称源自于下游服务(可能是个数据库)在授权调用者时信任上游服务。图 1 显示了此模式。请特别注意信任界限。在本示例中,数据库 信任 中间层可以授权调用者,并只允许经授权的调用者通过受信任的身份访问数据库。
![](https://i-blog.csdnimg.cn/blog_migrate/a231d47ed84118cc0e2ca07e37dc36b9.png)
在受信任的子系统模式中,资源的访问步骤如下:
• | 验证用户身份 |
• | 将用户映射到角色 |
• | 基于角色成员授权 |
• | 使用固定的受信任身份访问下游资源管理器 |
固定身份
用于访问下游系统和资源管理器的固定身份通常由预配置的 Windows 帐户(也称为服务帐户)提供。在 Microsoft SQL Server 资源管理器中,这意味着对 SQL Server 使用 Windows 身份验证。
另外,有些应用程序使用指定的 SQL 帐户(由连接字符串中的用户名和密码指定)访问 SQL Server。在这种情况下,必须为数据库配置 SQL 身份验证。
有关与 SQL Server 通信时 Windows 和 SQL 身份验证的相对优缺点的更多信息,请参考“数据访问安全性”这一章。
使用多个受信任的身份
有些资源管理器可能需要根据调用者的角色成员,执行更进一步细分的授权。例如,您可能有两组用户,一组应该授权可执行读/写操作,而另一组应该授权执行只读操作。
请看下面的 SQL Server 方法:
• | 创建两个 Windows 帐户,一个用于读操作,另一个用于读/写操作。 更通常的情况是,用不同的帐户映射应用程序特定的角色。例如,您可能要让 Internet 用户使用一个帐户,让内部操作员和/或管理员使用另一个帐户。 |
• | 将每个帐户映射为由 SQL Server 用户定义的数据库角色,并为每个角色建立必要的数据库权限。 |
• | 将用户映射到应用程序中的角色,并使用角色成员身份确定连接到数据库之前模拟的帐户。 |
这种方法如图 2 所示。
![](https://i-blog.csdnimg.cn/blog_migrate/ad91d6a10cf947233d1d27fb56fb48b5.png)
图 2. 使用多个身份访问数据库以支持更细分的授权
模拟/委派模式
在这种模式下,服务或组件在客户端访问下一个下游服务之前(通常在逻辑业务服务层中的某处)(使用操作系统级模拟)模拟客户端的身份。如果下一个服务位于同一台计算机,则模拟就足够了。如果下游服务位于一台远程计算机,则还需要委派。
委派的结果是,用于下游资源访问的安全上下文是该客户端的安全上下文。使用此模式通常有两个原因:
• | 它允许下游服务通过原调用者的身份执行每调用者授权。 |
• | 它允许下游服务使用操作系统级审核功能。 |
作为这种技术的一个具体示例,中间层 Enterprise Services 组件可以在调用者访问一个数据库之前对其进行模拟。使用依赖于原调用者安全上下文的数据库连接访问数据库。在此模式下,数据库对每个调用者进行身份验证,并根据指派给各个调用者的身份(或该调用者的 Windows 组成员)的权限做出授权决定。模拟/委派模式如图 3 所示。
![](https://i-blog.csdnimg.cn/blog_migrate/90c81f456785abd9a52ff8cd38c13f11.png)
图 3. 模拟/委派模式
选择资源访问模式
受信任的子系统模式用于绝大多数 Internet 应用程序和大规模的 Intranet 应用程序,这主要是出于可扩展性因素考虑。而模拟模式则往往用于可扩展性不是主要问题的小规模应用程序和那些审核(由于非拒绝原因)是关键问题的应用程序。
模拟/委派模式的优点
模拟/委派模式的主要优点是审核(与数据接近)。审核可以让管理员跟踪试图访问特定资源的用户。通常,如果审核是在资源访问的准确时间、由访问资源的相同例程生成,则认为审核最具权威性。
模拟/委派模式是通过维护用于下游资源访问的用户安全上下文来支持这一点的。这样可以使后端系统权威地记录用户和所请求的访问。
模拟/委派模式的缺点
模拟/委派模式的相关缺点包括:
• | 技术挑战。大多数安全服务提供商不支持委派,Kerberos 是有名的例外。 执行模拟的进程要求有更高的特权(具体来说就是 作为操作系统的一部分 的执行特权)。(这限制适用于 Windows 2000,而不适用于 Windows .NET Server)。 |
• | 可扩展性。模拟/委派模式意味着您不能有效地使用数据库连接池,因为执行数据库访问的连接依赖于原调用者的不同安全上下文。这严重限制了应用程序扩展至大量用户的能力。 |
• | 更多的管理工作。在后端资源中维护 ACL 需要授予每个用户恰当的访问级别。当后端资源的数量增加(且用户数增加)时,就需要在管理 ACL 上投入大量的管理精力。 |
受信任的子系统模式的优点
受信任的子系统模式具有以下优点:
• | 可扩展性。受信任的子系统模式支持连接池,这是应用程序可扩展性的基本要求。连接池允许多个客户端重复使用可用的池连接。它非常适用此模式,因为无论调用者的身份是什么,所有后端资源访问都使用服务帐户的安全上下文。 |
• | 后端 ACL 管理工作减到最少。只有服务帐户访问后端资源(例如,数据库)。ACL 只针对这个身份进行配置。 |
• | 用户无法直接访问数据。在受信任的子系统模式中,只有中间层服务帐户被授权访问后端资源。因此,如果不通过应用程序(并且以应用程序授权为准),用户无法直接访问后端数据。 |
受信任的子系统模式的缺点
受信任的子系统模式有两个缺点:
• | 审核。为了在后端执行审核,可以显式地(在应用程序级别)将原调用者的身份传递到后端,并在那执行审核。必须信任中间层,而且确实有潜在的拒绝风险。另一种选择是,在中间层生成审核纪录,然后将它与后端审核纪录相关联(为此,必须确保服务器时钟是同步的)。 |
• | 增加服务器攻击危险。在受信任的子系统模式中,中间层服务被授权对后端资源的广泛访问。因此,安全受威胁的中间层服务就可能使攻击者更加容易地获得对后端资源的广泛访问权。 |
传递身份
分布式应用程序可以分成多个安全子系统。例如,前端 Web 应用程序、中间层 Web 服务、远程组件和数据库代表四个不同的安全子系统。每一个都执行身份验证和授权。
您必须识别出那些必须将调用者身份(和相关的安全上下文)传递到下游子系统的子系统,这样才能支持针对原调用者的授权。
应用程序与操作系统身份传递对比
身份传递策略包括使用操作系统的委派功能或在应用程序级传递票证和/或凭证。例如:
• | 为了在应用程序级传递身份,一般使用方法参数或存储过程参数传递凭证(或票证)。 注:携带经过身份验证的调用者身份的GenericPrincipal 对象并不会在进程间自动传递。这需要自定义代码。 可以向存储过程传递允许您检索和处理用户特定数据的参数。例如: SELECT CreditLimit From Table Where UserName="Bob" 这种方法有时也称为 受信任的查询参数 方法。 |
• | 操作系统身份传递需要一种扩展形式的模拟(称为委派)。 |
模拟和委派
在典型情况下,服务器应用程序中的线程使用服务器进程的安全上下文运行。组成进程安全上下文的属性由进程的登录会话维护,并由进程级 Windows 访问令牌公开。所有本地和远程资源访问都通过进程级安全上下文执行,而该安全上下文则由用于运行服务器进程的 Windows 帐户确定。
模拟
为服务器应用程序配置了模拟后,模拟令牌就会附加到用于处理请求的线程上。模拟令牌代表通过身份验证的调用者(或匿名用户)的安全上下文。任何本地资源访问都是通过导致使用调用者安全上下文的线程模拟令牌执行的。
委派
如果服务器应用程序线程试图访问远程资源,则需要委派。具体地讲,被模拟的调用者的令牌必须具有网络凭证。如果没有,所有的远程资源访问都是以匿名用户 (AUTHORITY/A否NYMOUS LOGON) 执行的。
有许多因素可以决定是否可以委派安全上下文。表 1 显示了各种 IIS 身份验证类型,并对每种类型注明是否可以委派通过身份验证的调用者的安全上下文。
表 1:IIS 身份验证类型 | ||
身份验证类型 | 是否可以委派 | 备注 |
匿名 | 视情况而定 | 如果匿名帐户(默认为 IUSR_MACHINE)在 IIS 中被配置为本地帐户,那么,除非本地(Web 服务器)和远程计算机有同样的本地帐户(具有匹配的用户名和密码),否则不能委派它。 如果匿名帐户是域帐户,则可以委派它。 |
基本 | 是 | 如果对本地帐户使用基本身份验证,并且只要本地和远程计算机的本地帐户一致,就可以委派它。也可以委派域帐户。 |
简要 | 否 | - |
集成 Windows | 视情况而定 | 集成 Windows 身份验证导致 NTLM 或 Kerberos(取决于客户端和服务器的操作系统版本)。 NTLM 不支持委派。 Kerberos 支持有恰当配置环境的委派。 有关详细信息,请参考“How To Implement Kerberos Delegation for Windows 2000”。 |
客户端证书 | 视情况而定 | 如果与 IIS 证书映射一起使用,并且证书映射到远程计算机上复制的本地帐户或者映射到域帐户,则可以委派。 这可行的原因是映射帐户的凭证存储在本地服务器上,并且用于创建(具有网络凭证的)交互式的登录会话。 Active Directory 证书映射不支持委派。 |
重要: Windows 2000 下的Kerberos 委派是不受限制的。换句话说,用户或许可以在多台远程计算机之间制造多个网络跃点。为了消除这种潜在的安全风险,应该限制域帐户的访问范围,方法是从“域用户”组中删除此帐户,并只允许使用此帐户登录到特定的计算机。
基于角色授权
大部分 .NET Web 应用程序都使用基于角色的授权方法。您需要考虑各种角色类型,选择最适合您的应用程序方案的方法。您有以下选项:
• | .NET 角色 |
• | Enterprise Services (COM+) 角色 |
• | SQL Server 用户定义的数据库角色 |
• | SQL Server 应用程序角色 |
.NET 角色
.NET 角色非常灵活,它围绕 IPrincipal 对象展开,这些对象包含通过身份验证的身份所属的角色列表。.NET 角色可以用于 Web 应用程序、Web 服务,或驻留在 ASP.NET (用 HttpChannel 访问)中的远程组件。
授权可以通过 .NET 角色以两种方式进行:一种以声明方式用 PrincipalPermission 命令,一种以编程方式,在代码中用强制的 PrincipalPermission 命令或 IPrincipal.IsInRole 方法。
Windows 身份验证中的 .NET 角色
如果您的应用程序使用 Windows 身份验证,则 ASP.NET 会自动构建一个 WindowsPrincipal,并将其附加到当前 Web 请求的上下文(使用 HttpContext.User)。身份验证过程完成,并且 ASP.NET 将对象附加到当前请求后,它就可用于所有后续的基于 .NET 角色的授权了。
通过身份验证的调用者的 Windows 组成员用于确定角色集。在 Windows 身份验证下,.NET 角色与 Windows 组相同。
非 Windows 身份验证中的 .NET 角色
如果您的应用程序使用非 Windows 身份验证机制(例如表单或 Passport),那么您必须编写代码来创建 GenericPrincipal 对象(或自定义 IPrincipal 对象),并用从自定义身份验证数据存储(如 SQL Server 数据库)中获得的角色集填充它。
自定义 IPrincipal 对象
基于 .NET 角色的安全机制是可扩展的。您可以开发实现 IPrincipal 和 IIdentity 的自有类,并提供您自己的基于角色的扩展授权功能。
只要自定义 IPrincipal 对象(包含从自定义数据存储中获得的角色)(通过 HttpContext.User)附加到当前请求的上下文,就保证了基本角色的检查功能。
通过实现 IPrincipal 接口,可以确保声明和命令形式的PrincipalPermission 命令都适用于您的自定义身份。另外,您可以实现扩展的角色语义;例如,提供允许您测试和断言多个角色的成员身份的其他方法,比如 IsInMultipleRoles( string [] roles )。
更多信息
• | 有关基于 .NET 角色的授权的更多信息,请参考“ASP.NET 安全性”一章。 |
• | 有关创建 GenericPrincipal 对象的更多信息,请参考“How To Create GenericPrincipal Objects with 表单 Authentication”一章。 |
Enterprise Services (COM+) 角色
使用 Enterprise Services (COM+) 角色可以将访问检查交给中间层,并允许您在连接到后端数据库时使用数据库连接池。然而,对于有意义的基于 Enterprise Services (COM+) 角色的授权,前端 Web 应用程序必须模拟原调用者的身份,并(通过 Windows 访问令牌)使将其传递到 Enterprise Services 应用程序。为此,必须在 Web 应用程序的 Web.config 文件中放入以下各项。
<authentication mode="Windows" /> <identity impersonate="true" />
如果使用方法级的说明性检查(以确定哪些用户可以调用哪些方法)就足够的话,则可以使用“组件服务”管理工具部署应用程序和更新角色成员。
如果需要用方法代码以编程方式进行检查,您将会失去 Enterprise Services (COM+) 角色的一些管理和部署优点,因为角色逻辑是硬编码的。
SQL Server 用户定义的数据库角色
在这种方法中,您在数据库中创建角色,根据角色指派权限,并将 Windows 组和用户帐户映射到角色。这种方法要求您将调用者身份传递到后端(如果您对 SQL Server 使用首选的 Windows 身份验证)。
SQL Server 应用程序角色
在这种方法中,将权限授予数据库中的角色,但 SQL Server 应用程序角色不包含用户和组帐户。因此,您就会失去原调用者的粒度。
在应用程序角色中,您被授权访问特定的应用程序(与一组用户相对)。此应用程序使用接受角色名和密码的内置存储过程激活角色。这种方法的一个主要缺点是它要求应用程序安全地管理凭证(角色名和相关的密码)。
更多信息
有关 SQL Server 用户定义的数据库角色和应用程序角色的更多信息,请参考“数据访问安全性”一章。
.NET 角色与 Enterprise Services (COM+) 角色的对比
以下表格列出 .NET 角色和 Enterprise Services (COM+) 角色的功能对比。
表 2:Enterprise Services 角色与 .NET 角色的对比 | ||
功能 | Enterprise Services 角色 | .NET 角色 |
管理 | 组件服务管理工具 | 自定义 |
数据存储 | COM+ 目录 | 自定义数据存储(如 SQL Server 或 Active Directory) |
声明性 | 是 | 是 |
命令性 | 是 | 是 |
类、接口和方法级粒度 | 是 | 是 |
可扩展性 | 否 | 是(使用自定义 IPrincipal 实现) |
可供所有 .NET 组件使用 | 只供派生自 ServicedComponent 基类的组件使用 | 是 |
角色成员 | 角色包含 Windows 组或用户帐户 | 当使用 WindowsPrincipal 时,角色是 Windows 组–—没有额外的抽象级别 |
要求显式地实现接口 | 是,要想获得方法级的授权,必须显式地定义和实现接口 | 否 |
使用 .NET 角色
可以使用 .NET 角色保护以下各项的安全:
• | 文件 |
• | 文件夹 |
• | Web 页面(.aspx 文件) |
• | Web 服务(.asmx 文件) |
• | 对象 |
• | 方法和属性 |
• | 方法中的代码块 |
可以使用 .NET 角色保护操作(由方法和属性执行)和特定代码块的事实,意味着您可以保护对应用程序所访问的本地和远程资源的访问。
注 前面列表中的前四项(文件、文件夹、Web 页面和 Web 服务)是通过 UrlAuthorizationModule 保护的,它可以使用调用者的角色成员(和调用者的身份)做出授权决定。
如果您使用 Windows 身份验证,则系统会为您完成使用 .NET 角色所需的大部分工作。ASP.NET 会构建 WindowsPrincipal 对象,并由用户的 Windows 组成员确定相关的角色集。
要在非 Windows 身份验证机制中使用 .NET 角色,必须编写代码执行以下操作:
• | 捕获用户凭证。 |
• | 检验用户访问自定义数据存储(比如 SQL Server 数据库)的凭证。 |
• | 检索角色列表,构建 GenericPrincipal 对象并将它与当前 Web 请求相关联。 GenericPrincipal 对象代表通过身份验证的用户,并用于后续的 .NET 角色检查,例如声明性的PrincipalPermission 命令和编程方式的IPrincipal.IsInRole 检查。 |
更多信息
有关为表单身份验证创建 GenericPrincipal 对象所涉及过程的更多信息,请参考“ASP.NET 安全性”一章。
检查角色成员
可使用以下类型的 .NET 角色检查:
重要:.NET 角色检查依赖于 IPrincipal 对象(表示通过身份验证的用户)是否与当前请求关联。对于 ASP.NET Web 应用程序,IPrincipal 对象必须附加到 HttpContext.User。对于 Windows 窗体应用程序,IPrincipal 对象必须附加到 Thread.CurrentPrincipal。
• | 手动角色检查。对于细分授权,您可以调用 IPrincipal.IsInRole 方法,根据调用者的角色成员授权对特定代码块的访问。在检查角色成员时,AND 和 OR 逻辑均可使用。 |
• | 声明性角色检查(方法入口)。您可以使用 PrincipalPermissionAttribute 类(可以简写为 PrincipalPermission)对方法进行注释,以声明方式请求角色成员。这些检查只支持 OR 逻辑。例如,您可以要求调用者至少属于一个特定的角色(例如,调用者必须是出纳员或一个经理)。不能用声明性检查指定调用者必须既是经理,又是出纳员。 |
• | 命令性角色检查(在方法中检查)。可以在代码中调用 PrincipalPermission.Demand 执行细分授权逻辑。支持逻辑 AND 和 OR 操作。 |
角色检查示例
以下代码片段显示了一些使用编程、声明性和命令性方法的角色检查示例。
授权 Bob 执行操作:
注 尽管可以授权个别用户,但通常应该基于角色成员身份进行授权,这使您可以授权在应用程序中共享相同特权的用户组。
• | 直接用户名检查 GenericIdentity userIdentity = new GenericIdentity("Bob"); if (userIdentity.Name=="Bob") { } |
• | 声明性检查 [PrincipalPermissionAttribute(SecurityAction.Demand, User="Bob")] public void DoPrivilegedMethod() { } |
• | 命令性检查 PrincipalPermission permCheckUser = new PrincipalPermission( "Bob", null); permCheckUser.Demand(); |
授权出纳员执行操作:
• | 直接角色名检查 GenericIdentity userIdentity = new GenericIdentity("Bob"); // Role names would be retrieved from a custom data store string[] roles = new String[]{"Manager", "Teller"}; GenericPrincipal userPrincipal = new GenericPrincipal(userIdentity, roles); if (userPrincipal.IsInRole("Teller")) { } |
• | 声明性检查 [PrincipalPermissionAttribute(SecurityAction.Demand, Role="Teller")] void SomeTellerOnlyMethod() { } |
• | 命令性检查 public SomeMethod() { PrincipalPermission permCheck = new PrincipalPermission( null,"Teller"); permCheck.Demand(); // Only Tellers can execute the following code // •ñn members of the Teller role result in a security exception . . . } |
授权经理或出纳员执行操作:
• | 直接角色名检查 if (Thread.CurrentPrincipal.IsInRole("Teller") || Thread.CurrentPrincipal.IsInRole("Manager")) { // Perform privileged operations } |
• | 声明性检查 [PrincipalPermissionAttribute(SecurityAction.Demand, Role="Teller"), PrincipalPermissionAttribute(SecurityAction.Demand, Role="Manager")] public void DoPrivilegedMethod() { } |
• | 命令性检查 PrincipalPermission permCheckTellers = new PrincipalPermission( null,"Teller"); PrincipalPermission permCheckManagers = new PrincipalPermission( null,"Manager"); (permCheckTellers.Union(permCheckManagers)).Demand(); |
授权那些既是经理又是出纳员的用户执行操作:
• | 直接角色名检查 if (Thread.CurrentPrincipal.IsInRole("Teller") && Thread.CurrentPrincipal.IsInRole("Manager")) { // Perform privileged operation } |
• | 声明性检查 不可以利用 .NET 角色以声明方式执行 AND 检查。将 PrincipalPermission 命令叠加在一起使用会产生逻辑 OR。 |
• | 命令性检查 PrincipalPermission permCheckTellers = new PrincipalPermission( null,"Teller"); permCheckTellers.Demand(); PrincipalPermission permCheckManagers = new PrincipalPermission( null, "Manager"); permCheckManagers.Demand(); |
选择身份验证机制
本部分提供指导信息,旨在帮助您选择常见应用程序方案的身份验证机制。您应该考虑从以下问题着手:
• | 身份。仅当应用程序用户的 Windows 帐户可由受信任的机构进行身份验证,并且应用程序的 Web 服务器可以访问该机构时,才适合使用 Windows 身份验证机制。 | ||||||||||||||||||||||||
• | 凭证管理。Windows 身份验证的一个主要优点是它使您可以将凭证管理交给操作系统去做。采用非 Windows 方法(如表单身份验证),您就必须仔细考虑用户凭证的存储位置和方式。两种最常见的方法是使用:
有关将 SQL Server 用作凭证存储的安全考虑事项的更多信息,请参考“数据访问安全性”一章。 有关在自定义数据存储(包括 Active Directory)中使用表单身份验证的更多信息,请参考“ASP.NET 安全性”一章。 | ||||||||||||||||||||||||
• | 身份传递。您需要实现模拟/委派模式,并在操作系统级的各层间传递原调用者的安全上下文吗?例如,为了支持审核或每用户(粒度)授权。如果需要,您就需要能够模拟调用者,并将它们的安全上下文委派到下一个下游子系统,如本章前面的“传递身份”部分中的“委派”主题所描述的。 | ||||||||||||||||||||||||
• | 浏览器类型。您的用户都有 Internet Explorer 吗?或者您需要支持使用混合浏览器类型的用户群?表 3 阐述了哪些身份验证机制需要 Internet Explorer 浏览器,而哪些支持各种常见的浏览器类型。
|
Internet 方案
Internet 方案的基本假定条件是:
• | 用户在服务器域或该服务器可达的受信任域中没有 Windows 帐户。 |
• | 用户没有客户端证书。 |
图 4 显示了一个为 Internet 方案选择身份验证机制的决策树。
![](https://i-blog.csdnimg.cn/blog_migrate/6c267d9e3c72b38525a7f18e2fed1f55.png)
图 4. 为 Internet 应用程序选择身份验证机制
有关 Web 服务安全和 WS 安全规范(全球 XML 体系结构 (GXA) 倡议的一部分)的更多信息,请参考“Web Services Security”一章。
表单/ Passport 比较
这一部分总结表单和 Passport 身份验证的相对优点。
表单身份验证的优点
• | 支持对照自定义数据存储(通常为 SQL Server 数据库或 Active Directory)的身份验证。 |
• | 支持基于角色授权(包括从数据存储中查找角色)。 |
• | 与 Web 用户界面平稳集成。 |
• | ASP.NET 提供结构的大部分。与传统 ASP 相比,需要的自定义代码相对较少。 |
Passport 身份验证的优点
• | Passport 是一种集中式解决方案。 |
• | 它不需要应用程序进行凭证管理。 |
• | 能与基于角色授权方案一起使用。 |
• | 非常安全,因为它建立在加密技术之上。 |
更多信息
• | 有关 Web 服务身份验证方法的更多信息,请参考“Web Services Security”一章。 |
• | 有关在 SQL Server 中使用表单身份验证的更多信息,请参考“How To Use 表单 Authentication with SQL Server 2000”一章。 |
Intranet / Extranet 方案
图 5 显示了一个可用于帮助为 Intranet 和 Extranet 应用方案选择一种身份验证机制的决策树。
![](https://i-blog.csdnimg.cn/blog_migrate/426cd7bbbc6a958acc4d1a09898b818c.png)
图 5. 为 Intranet 和 Extranet 应用程序选择一种身份验证机制
身份验证机制比较
以下表格显示可用的身份验证机制的比较。
表 4:可用的身份验证方法 | |||||||
- | Basic | Digest | NTLM | Kerberos | Certs | Forms | Passport |
用户在服务器的域中需要 Windows 帐户 | 是 | 是 | 是 | 是 | 否 | 否 | 否 |
支持委派* | 是 | 否 | 否 | 是 | 可以 | 是 | 是 |
需要 Win2K 客户端和服务器 | 否 | 是 | 否 | 是 | 否 | 否 | 否 |
以明文形式传递凭证(需要 SSL) | 是 | 否 | 否 | 否 | 否 | 是 | 否 |
支持非 IE 浏览器 | 是 | 否 | 否 | 否 | 是 | 是 | 是 |
* 有关详细内容,请参考本章前面的“传递身份”部分中的“委派”主题。
小结
设计分布式应用程序的身份验证和授权方法是一项具有挑战性的任务。在应用程序开发的早期阶段,正确设计身份验证和授权有助于减少许多主要的安全风险。以下总结本章中的信息:
• | 使用受信任子系统资源访问模式可获得使用数据库连接池的益处。 |
• | 如果您的应用程序没有使用 Windows 身份验证,请使用 .NET 角色检查提供授权。对照自定义数据存储检验凭证,检索角色列表并创建 GenericPrincipal 对象。将它与当前 Web 请求 (HttpContext.User) 相关联。 |
• | 如果您的应用程序使用 Windows 身份验证,但不使用 Enterprise Services,请使用 .NET 角色。请记住,对于 Windows 身份验证,.NET 角色为 Windows 组。 |
• | 如果您的应用程序使用 Windows 身份验证和 Enterprise Services,请考虑使用 Enterprise Services (COM+) 角色。 |
• | 对于使用 Enterprise Services (COM+) 角色的有意义的基于角色授权,原调用者的身份必须传递到 Enterprise Services 应用程序。如果从 ASP.NET Web 应用程序中调用 Enterprise Services 应用程序,则意味着 Web 应用程序必须使用 Windows 身份验证,并配置为使用模拟。 |
• | 以 PrincipalPermission 属性对方法进行注释,以声明方式请求角色成员。如果调用者不在指定的角色中,则不调用该方法,并且产生一个安全异常。 |
• | 在方法代码中调用 PrincipalPermission.Demand (或使用 IPrincipal.IsInRole)以获得细分授权决策。 |
• | 考虑实现自定义 IPrincipal 对象以获得其他角色检查语义 |