构建安全的 ASP.NET 应用程序
身份验证、授权和安全通信
J.D. Meier、Alex Mackman、Michael Dunner 和 Srinath Vasireddy
Microsoft Corporation
2002 年 10 月
** ASP.NET 安全性 **
_总结 _
本章提供用于构建安全的 ASP.NET Web 应用程序的指南和建议。本章提供的大多数指南和建议同样适用于开发 ASP.NET Web 服务和由 ASP.NET 驻留的 .NET Remoting 对象。
_内容 _
- ASP.NET 安全体系结构
- 身份验证和授权
- 配置安全性
- 编程安全性
- Windows 验证
- 表单身份验证
- Passport 身份验证
- 自定义身份验证
- ASP.NET 的进程标识
- 模拟
- 访问系统资源
- 访问网络资源
- 安全通信
- 存储机密
- 保护会话和视图状态
- 网络场注意事项
- 总结
**
ASP.NET 安全体系结构 **
ASP.NET 与 IIS、.NET 框架和操作系统所提供的基础安全服务配合使用,共同提供一系列身份验证和授权机制。图 8.1 中总结了这些情况。
图 8.1 ASP.NET 安全服务
图 8.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 配置为使用表单身份验证,将根据数据存储(通常为 Microsoft® SQL Server® 数据库或 Active Directory® 目录服务)对调用方提供的凭据进行身份验证(使用 HTML 表单)。如果将 ASP.NET 配置为使用 Passport 身份验证,则将用户重定向到 Passport 站点,然后 Passport 身份验证服务对用户进行身份验证。
6. ASP.NET 授权访问所请求的资源或操作。
** UrlAuthorizationModule ** (系统提供的 HTTP 模块)使用在 Web.config 中配置的授权规则(具体来说就是
1<authorization> 元素),确保调用方可以访问所请求的文件或文件夹。
2在 Windows 身份验证中,FileAuthorizationModule(另一个 HTTP 模块)检查调用方是否具有访问所请求资源的必要权限。将调用方的访问令牌与保护资源的 ACL 进行比较。
3也可以使用 .NET 角色(以声明方式或编程方式)确保给调用方授予访问所请求资源或执行所请求操作的权限。
4 7. 应用程序中的代码使用特定标识来访问本地和/或远程资源。默认情况下,ASP.NET 不执行模拟,因此,配置的 ASP.NET 进程帐户提供标识。也可以选择原调用方的标识(如果启用了模拟)或已配置的服务标识。
5
6
7
8**_网关守卫_ **
9ASP.NET Web 应用程序中的授权点(或关守)是由 IIS 和 ASP.NET 提供的:
10
11_**IIS** _
12如果关闭了匿名身份验证,则 IIS 只允许来自特定用户的请求,即它可以在其自己的域或受信任域中验证这些用户的身份。
13对于静态文件类型(例如 .jpg、.gif 和 .htm 文件,即没有映射到 ISAPI 扩展的文件),IIS 使用与所请求文件关联的 NTFS 权限执行访问控制。
14
15** _ASP.NET_ **
16ASP.NET 关守包括 **UrlAuthorizationModule** 、 **FileAuthorizationModule** 以及主体权限要求和角色检查。
17
18> ** **UrlAuthorizationModule** **
19> 可以配置应用程序 Web.config 文件中的 <authorization> 元素,控制哪些用户和用户组可以访问应用程序。授权是以存储在 HttpContext.User 中的 IPrincipal 对象为基础。
20>
21> **FileAuthorizationModule**
22> 对于由 IIS 映射到 ASP.NET ISAPI 扩展 (Aspnet_isapi.dll) 的文件类型,使用已验证用户的 Windows 访问令牌(可能为 IUSR_MACHINE),根据附加到所请求的 ASP.NET 文件中的 ACL 自动执行访问检查。
23>
24> * * *
25>
26> **注意** :要进行文件授权,并不要求模拟.
27>
28> * * *
29>
30> **FileAuthorizationModule** 类仅对所请求的文件执行访问检查,而不对所请求页面中的代码访问的文件执行访问检查,但 IIS 对这些文件执行访问检查。
31> 例如,如果您请求 Default.aspx 并且它包含一个嵌入的用户控件 (Usercontrol.ascx),该控件又包含一个图像标记(指向 Image.gif),则 FileAuthorizationModule 对 Default.aspx 和 Usercontrol.ascx 执行访问检查,因为 IIS 将这些文件类型映射到 ASP.NET ISAPI 扩展。
32> FileAuthorizationModule 不对 Image.gif 执行检查,因为它是由 IIS 内部处理的静态文件。但是,由于 IIS 对静态文件执行访问检查,因此,仍须使用进行相应配置的 ACL 给已验证用户授予读取该文件的权限。
33> 图 8.2 中显示了此方案。
34>
35> * * *
36>
37> **系统管理员注意事项:** 需要给已验证用户授予读取此方案中涉及的所有文件的 NTFS 权限。唯一的变化是使用哪个关守来执行访问控制。ASP.NET 进程帐户只需要读取 ASP.NET 注册文件类型的访问权限。
38>
39> * * *
40>
41> 
42> 图 8.2 _IIS 和 ASP.NET 关守一起使用_
43>
44> 在此方案中,您可以在文件入口处禁止访问。如果您配置了附加到 Default.aspx 的 ACL 并且拒绝访问某个特定的用户,则 Default.aspx 中的代码无法将用户控件或任何嵌入图像发送到客户端。如果该用户直接请求图像,则 IIS 亲自执行访问检查。
45>
46> **主体权限要求和明确的角色检查**
47> 除了可以用 IIS 和 ASP.NET 配置的关守外,还可以将主体权限要求(以声明方式或编程方式)用作附加的细分访问控制机制。通过使用主体权限检查(由 PrincipalPermissionAttribute 类执行),您可以根据各个用户的标识和组成员身份(由附加到当前线程的 IPrincipal 对象定义)控制对类、方法或个别代码块的访问。
48>
49>
50> * * *
51>
52> 注意:用于请求角色成员身份的主体权限要求与调用 IPrincipal.IsInRole 来测试角色成员身份不同;如果调用方不是指定角色的成员,则前者产生异常,而后者仅返回一个布尔值以确认角色成员身份。
53>
54>
55> * * *
56>
57> 在 Windows 身份验证中,ASP.NET 自动将一个代表已验证身份用户的 WindowsPrincipal 对象连接到当前的 Web 请求(使用 HttpContext.User)。表单身份验证和 Passport 身份验证创建具有相应标识但没有角色的 GenericPrincipal 对象,并将它附加到 HttpContext.User。
58>
59> **更多信息**
60>
61> * 有关配置安全性的详细信息,请参见本章后面的“配置安全性”。
62> * 有关编程安全性(和 IPrincipal 对象)的详细信息,请参见本章后面的“编程安全性”。
63>
64
65
66**
67身份验证和授权策略 **
68
69ASP.NET 提供了若干以声明方式和编程方式进行授权的机制,这些机制可与各种身份验证方案配合使用。这样,您就可以开发深入的授权策略以及可以配置为提供各种粒度级别(例如,基于角色的每用户或每用户组)的授权策略。
70本节说明一组常用身份验证选项的可用授权选项(可进行配置和编程)。
71下面概述了身份验证选项:
72* 带模拟的 Windows 身份验证
73* 不带模拟的 Windows 身份验证
74* 使用固定身份的 Windows 身份验证
75* 表单身份验证
76* Passport 身份验证 **_可用的授权选项_ **
77
78下表列出了一组可用的授权选项。对于每个选项,该表都指出了是否需要 Windows 身份验证和/或模拟。如果特定授权选项不需要 Windows 身份验证,则该选项适用于所有其他的身份验证类型。可以使用该表优化身份验证/授权策略。
79表 8.1: _Windows 身份验证和模拟要求_ | 授权选项 | 需要 Windows 身份验证 | 需要模拟
80---|---|---
81FileAuthorizationModule | 是 | 否
82UrlAuthorizationModule | 否 | 否
83主体权限要求 | 否 | 否
84.NET 角色 | 否 | 否
85Enterprise Services 角色 | 是 | 是(在 ASP.NET Web 应用程序中)
86NTFS 权限(用于直接请求的静态文件类型;没有映射到 ISAPI 扩展的文件类型) | 不适用 – ASP.NET 不处理这些文件。 在任何(非匿名)IIS 身份验证机制中,应为各个已验证的用户配置权限。 在匿名身份验证中,应为 IUSR_MACHINE 配置权限。 | 否(IIS 执行访问检查。)
87NTFS 权限(用于 Web 应用程序代码访问的文件) | 否 | 否 如果使用模拟,请根据模拟的 Windows 标识配置 ACL,该标识可以是原调用方,也可以是 Web.config 中的 < **identity** > 元素指定的标识。*
88* 模拟的标识可以是原调用方,也可以是 Web.config 中的 < ** identity ** > 元素指定的标识。请看下面两个 < ** identity ** > 元素。
89
90<identity impersonate="true"></identity>
91<identity impersonate="true" password="pwd" username="Bob"></identity>
92
93第一种配置导致模拟原调用方(已由 IIS 验证了身份),而第二种配置导致模拟标识 Bob。由于以下两个原因,建议不要使用第二种配置:
94
95 * 它要求您在 Microsoft Windows? 2000 操作系统上为 ASP.NET 进程标识授予“充当操作系统的一部分”权限。
96 * 它还要求您在 Web.config 中包含纯文本密码。
97
98
99
100下一个 .NET 框架版本将取消这两个限制。
101
102**_带模拟的 Windows 身份验证_ **
103
104> 以下配置元素向您显示了如何明确启用 Web.config 或 Machine.config 中的 Windows (IIS) 身份验证和模拟。
105>
106>
107> * * *
108>
109> 注意:应根据每个应用程序的具体情况,在应用程序的 Web.config 文件中配置身份验证。
110>
111> * * *
112>
113>
114> <authentication mode="Windows"></authentication>
115> <identity impersonate="true"></identity>
116>
117> 在此配置中,ASP.NET 应用程序代码模拟已由 IIS 验证身份的调用方。
118> **_
119> 可配置的安全设置 _ **
120> 当您将 Windows 身份验证和模拟功能一起使用时,就可以使用下列授权选项:
121>
122>> **Windows ACL**
123>>
124>> * 客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用方的访问令牌和附加到请求资源的 ACL 以便执行访问检查。
125> 对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用方的访问令牌和附加到文件的 ACL 执行访问检查。
126>> * 应用程序访问的资源。可以根据原调用方,在应用程序访问的资源(文件、文件夹、注册表项和 Active Directory 对象等)上配置 Windows ACL。
127>>
128
129>>
130>> ** URL 授权 ** 在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 的格式,并且角色与 Windows 组一一对应。
131>>
132>> <authorization>
133> <deny user="DomainName\UserName"></deny>
134> <allow roles="DomainName\WindowsGroup"></allow>
135> </authorization>
136>>
137>> ** Enterprise Services (COM+) ** 角色。角色保存在 COM+ 目录中。可以使用“组件服务”管理工具或脚本配置角色。
138>
139> _**编程安全性** _
140> 编程安全性是指 Web 应用程序代码中的安全检查。在您使用 Windows 身份验证和模拟功能时,可以使用下列程序安全设置选项:
141>
142>> ** PrincipalPermission 请求 **
143>>
144>> * 命令性(嵌入方法的代码内)
145> PrincipalPermission permCheck = new PrincipalPermission(
146> null, @"DomainName\WindowsGroup");
147> permCheck.Demand();
148>> * 声明性(属性位于接口、类和方法之前)
149> [PrincipalPermission(SecurityAction.Demand,
150> Role=@"DomainName\WindowsGroup)]
151>>
152
153>>
154>> **明确的角色检查** 您可以使用 IPrincipal 接口执行角色检查。
155> IPrincipal.IsInRole(@"DomainName\WindowsGroup");
156>>
157>> ** Enterprise Services (COM+) 角色 ** 可以使用 ContextUtil 类以编程方式执行角色检查。ContextUtil.IsCallerInRole("Manager")
158>
159> _**
160> 何时使用 ** _
161> 使用 Windows 身份验证和模拟的情况:
162>
163> * 应用程序的用户已经有了可以由服务器验证的 Windows 帐户。
164> * 您需要将原调用方的安全性上下文传递到 Web 应用程序的中间层和/或数据层以支持细分(每用户)授权。
165> * 您需要将原调用方的安全性上下文传递到下游各层以支持操作系统级审核。
166>
167
168>
169> 在应用程序中使用模拟之前,确保将此方法与使用受信任的子系统模型进行比较,了解此方法的优缺点。第 3 章“身份验证和授权”中的“选择资源访问模型”详细阐述了这些内容。
170> 模拟的缺点包括:
171>
172> * 由于无法有效地对数据库连接进行池处理,因而降低了应用程序的可伸缩性。
173> * 由于需要给各个用户配置后端资源的 ACL,因而增加了管理工作。
174> * 委派需要 Kerberos 身份验证和进行适当配置的环境。
175>
176> **更多信息**
177>
178> * 有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。
179> * 有关模拟的详细信息,请参见本章后面的“模拟”。
180> * 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。
181> * 有关 Enterprise Services (COM+) 角色的详细信息,请参见第 9 章“Enterprise Services 安全性”。
182> * 有关 PrincipalPermission 要求的详细信息,请参见本指南“入门”部分的“主体”。
183>
184
185
186**_不带模拟的 Windows 身份验证 _ **
187
188> 下列配置元素显示了如何在 Web.config 中明确声明启用不带模拟功能的 Windows (IIS) 身份验证。
189>
190> <authentication mode="Windows"></authentication>
191> <!-- The following setting is equivalent to having no identity element -->
192> <identity impersonate="false"></identity>
193>
194> **_可配置的安全设置_ **
195> 当您使用不带模拟的 Windows 身份验证时,可以使用以下授权选项:
196>
197>> **Windows ACL**
198>>
199>> * 客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用方的访问令牌和附加到请求资源的 ACL 以便执行访问检查。模拟不是必需选项。
200> 对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用方的访问令牌和附加到文件的 ACL 执行访问检查。
201>> * 应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。
202>>
203
204>>
205>> ** URL 授权 ** 在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 的格式,并且角色与 Windows 组一一对应。
206> <authorization>
207> <deny user="DomainName\UserName"></deny>
208> <allow roles="DomainName\WindowsGroup"></allow>
209> </authorization>
210>
211> _**程序安全性** _
212> 可以使用下列编程安全选项:
213>
214>> **主体权限要求**
215>>
216>> * 命令性
217> PrincipalPermission permCheck = new PrincipalPermission(
218> null, @"DomainName\WindowsGroup");
219> permCheck.Demand();
220>> * 说明性
221> [PrincipalPermission(SecurityAction.Demand,
222> Role=@"DomainName\WindowsGroup")]
223>>
224
225>>
226>> **明确的角色检查** 您可以使用 IPrincipal 接口执行角色检查。
227> IPrincipal.IsInRole(@"DomainName\WindowsGroup");
228>
229>
230> _**何时使用** _
231> 使用不带模拟的 Windows 身份验证的情况:
232>
233> * 应用程序的用户已经有了可以由服务器验证的 Windows 帐户。
234> * 需要使用固定标识来访问下游资源(例如数据库)以便支持连接池。
235>
236> **更多信息**
237>
238> * 有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。
239> * 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。
240> * 有关 PrincipalPermission 要求的详细信息,请参见本指南“入门”部分的“主体”。
241>
242
243
244**_使用固定标识的 Windows 身份验证_ **
245
246> Web.config 中的 <identity> 元素支持可选的用户名和密码属性,这样,您就可以为应用程序配置特定的固定标识以进行模拟。这显示在以下配置文件片段中。
247> <identity impersonate="true" username="DomainName\UserName"> password="ClearTextPassword" />
248>
249> **_何时使用_ **
250> 对于安全环境中的当前 .NET 框架版本(版本 1),由于以下两个原因,建议不要使用此方法:
251>
252> * 不应以纯文本形式将用户名和密码存储在配置文件中,尤其是存储在虚拟目录中的配置文件。
253> * 在 Windows 2000 上,此方式将强制您授予 ASP.NET 进程帐户“充当操作系统的一部分”权限。一旦攻击者攻击 Web 应用程序进程,这将会降低 Web 应用程序的安全性并增加潜在的威胁。
254>
255
256>
257> .NET 框架 1.1 版将在 Windows 2000 上提供此方案的改进版本:
258>
259> * 凭据将进行加密。
260> * 登录将由 IIS 进程执行,这样 ASP.NET 就不需要“充当操作系统的一部分”权限了。
261>
262
263
264_**表单身份验证** _
265
266> 以下配置元素显示了如何在 Web.config 中以声明方式启用表单身份验证。
267> <authentication mode="Forms">
268> <forms loginurl="logon.aspx" name="AuthCookie" path="/" timeout="60">
269> </forms>
270> </authentication>
271>
272> **_可配置的安全设置_ **
273> 在使用表单身份验证时,可以使用以下授权选项:
274>
275>> **Windows ACL**
276>>
277>> * 客户端请求的资源。请求的资源需要 ACL 以允许对匿名 Internet 用户帐户进行读取访问。(在使用表单身份验证时,应该将 IIS 配置为允许匿名访问)。
278> 无法使用 ASP.NET 文件授权,因为它需要 Windows 身份验证。
279>> * 应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。
280>>
281
282>>
283>> ** URL 授权 **
284> 在 Web.config 中配置 URL 授权。在表单身份验证中,用户名的格式取决于自定义数据存储、SQL Server 数据库或 Active Directory。
285>>
286>> * 如果使用的是 SQL Server 数据存储:
287>
288> <authorization>
289> <deny users="?"></deny>
290> <allow roles="Manager,Sales" users="Mary,Bob,Joe"></allow>
291> </authorization>
292>
293>> * 如果使用 Active Directory 作为数据存储,则以 X.500 格式显示用户名和组名:
294>
295> <authorization>
296> <deny users="[email protected]"></deny>
297> <allow roles="CN=Smith James,CN=FTE_northamerica,CN=Users,
298> DC=domain,DC=corp,DC=yourCompany,DC=com"></allow>
299> </authorization>
300>>
301
302>
303> _**
304> 程序安全性 ** _
305> 可以使用下列编程安全选项:
306>
307>> **主体权限要求**
308>>
309>> * 命令性
310>
311> PrincipalPermission permCheck = new PrincipalPermission(
312> null, "Manager");
313> permCheck.Demand();
314>
315>> * 说明性
316>
317> [PrincipalPermission(SecurityAction.Demand,
318> Role="Manager")]
319>>
320
321>>
322>> **明确的角色检查** 您可以使用 IPrincipal 接口执行角色检查。
323> IPrincipal.IsInRole("Manager");
324>
325>
326> _**何时使用** _
327> 表单身份验证最适合于 Internet 应用程序。如果出现以下情况,则应该使用表单身份验证:
328>
329> * 应用程序用户没有 Windows 帐户。
330> * 您希望用户通过使用 HTML 表单输入凭据的方式登录到应用程序。
331>
332> **更多信息**
333>
334> * 有关表单身份验证的详细信息,请参见本章后面的“表单身份验证”。
335> * 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。
336>
337
338
339**_ Passport 身份验证 _ **
340
341> 以下配置元素显示了如何在 Web.config 中以声明方式启用 Passport 身份验证。
342> <authentication mode="Passport"></authentication>
343>
344> **_何时使用_ **
345> 如果应用程序用户没有 Windows 帐户,并且您希望实现单次登录解决方案,则应该在 Internet 上使用 Passport 身份验证。如果用户以前使用 Passport 帐户在参与的 Passport 站点进行登录,则不必登录到使用 Passport 身份验证配置的站点。
346
347**配置安全性**
348
349本节说明配置 ASP.NET Web 应用程序安全性所需的实际步骤。图 8.3 中总结了这些情况。
350
351图 8.3 _配置 ASP.NET 应用程序安全性_
352
353**_配置 IIS 设置_ **
354要配置 IIS 安全性,您必须执行以下步骤:
355
356 1. (可选)安装 Web 服务器证书(如果需要 SSL 的话)。
357有关详细信息,请参见本指南的“参考”部分的“如何做:在 Web 服务器上设置 SSL”。
358 2. 配置 IIS 身份验证。
359 3. (可选)配置客户端证书映射(如果使用证书身份验证的话)。
360有关客户端证书映射的详细信息,请参见 Microsoft 知识库文章 Q313070“How to Configure Client Certificate Mappings in Internet Information Services (IIS) 5.0”(如何在 Internet 信息服务 (IIS) 5.0 中配置客户端证书映射)。
361 4. 设置文件和文件夹的 NTFS 权限。IIS 和 ASP.NET FileAuthorizationModule 共同检查已验证用户(或匿名 Internet 用户帐户)是否具有访问所请求文件的必要权限(根据 ACL 设置)。
362
363
364
365**_配置 ASP.NET 设置 _ **
366应用程序级别配置设置保存在 Web.config 文件中,这些文件位于应用程序的虚拟根目录或者(可选)其他子文件夹中(这些设置有时可以覆盖父文件夹设置)。
367
368> 1\. 配置身份验证。应该在应用程序虚拟根目录下的 Web.config 文件中基于每个应用程序对它进行设置(而不是在 Machine.config 中)。
369>
370> <authentication mode="Windows|Forms|Passport|None"></authentication>
371>
372> 2\. 配置模拟。默认情况下,ASP.NET 应用程序不使用模拟。应用程序使用配置的 ASP.NET 进程标识(通常为 ASPNET)运行,并且应用程序执行的所有资源访问都使用此标识。仅在以下情况下需要使用模拟:
373>
374> * 您使用 Enterprise Services 并且要使用 Enterprise Services (COM+) 角色授权访问服务组件所提供的功能。
375> * 将 IIS 配置为使用匿名身份验证,而且要使用匿名 Internet 用户帐户进行资源访问。有关此方法的详细信息,请参见本章后面的“访问网络资源”。
376> * 您需要将已验证用户的安全性上下文传递到下一层(例如数据库)。
377> * 您已将传统的 ASP 应用程序移植到 ASP.NET,并且需要同样的模拟行为。默认情况下,传统 ASP 模拟调用方。
378>
379> 要配置 ASP.NET 模拟,请在应用程序的 Web.config 中使用下面的 <identity> 元素。
380> <identity impersonate="true"></identity>
381>
382
383>
384> 3\. 配置授权。URL 授权确定用户或角色是否可以将特定的 HTTP 谓词(例如,GET、HEAD 和 POST)发送给特定的文件。要实现 URL 授权,请执行以下任务。
385>
386>> a. 将 <authorization> 元素添加到应用程序虚拟根目录下的 Web.config 文件中。
387>
388> b. 使用 allow 和 deny 属性限制对用户和角色的访问。下面的示例摘自 Web.config,它使用 Windows 身份验证并允许 Bob 和 Mary 的访问,但拒绝其他人的访问。
389> <authorization>
390> <allow users="DomainName\Bob, DomainName\Mary"></allow>
391> <deny users="*"></deny>
392> </authorization>
393>
394> 重要信息:您需要在 <authorization> 元素的结尾添加 <deny users="?"></deny> 或 <deny users="*"></deny>,否则将给所有已验证的标识授予访问权限。
395
396**_ URL 授权注意事项 _ **
397在配置 URL 授权时,请注意以下几点:
398
399 * "*" 指所有标识。
400 * "?" 指未经过验证的标识(即匿名标识)。
401 * 要使 URL 授权能够正常工作,并不需要进行模拟。
402 * Web.config 中的授权设置通常适用于当前目录和所有子目录中的所有文件(除非子目录包含它自己的 Web.config,并且该文件包含 <authorization> 元素。在这种情况下,子目录中的设置覆盖父目录的设置)。
403
404注意:URL 授权只适用于由 IIS 映射到 ASP.NET ISAPI 扩展 (aspnet_isapi.dll) 的文件类型。
405
406可以使用 <location> 标记将授权设置应用于个别文件或目录。下面的示例显示了如何将授权应用于特定的文件 (Page.aspx)。
407
408<location path="page.aspx"></location>
409<authorization>
410<allow users="DomainName\Bob, DomainName\Mary"></allow>
411<deny users="*"></deny>
412</authorization>
413</location>
414 * 用于 URL 授权的用户和角色是由身份验证设置决定的:
415 * 如果设置了 <authentication mode="”Windows”"></authentication>,则给 Windows 用户和组帐户授予访问权限。
416用户名采用“DomainName\WindowsUserName”的格式
417角色名采用“DomainName\WindowsGroupName”的格式
418
419注意:本地管理员组称为“BUILTIN\Administrators”。本地用户组称为“BUILTIN\Users”。
420
421 * 如果设置了 <authentication mode="”Forms”"></authentication>,则根据存储在当前 HTTP 上下文中的 IPrincipal 对象的用户和角色进行授权。例如,如果使用表单身份验证根据数据库验证用户的身份,则根据从数据库中检索的角色进行授权。
422
423 * 如果设置了 <authentication mode="”Passport”"></authentication>,则根据从存储中检索的 Passport 用户 ID (PUID) 或角色进行授权。例如,可以将 PUID 映射到特定的帐户和在 SQL Server 数据库或 Active Directory 中存储的一组角色。
424
425注意:此功能将被内置到 Microsoft Windows Server 2003 操作系统中。
426
427 * 如果设置了 <authentication mode="”None”"></authentication>,则不能执行授权。“None”指定您不想执行任何身份验证,或者不想使用任何 .NET 身份验证模块,而是使用您自己的自定义机制。
428但是,如果使用自定义身份验证,则应创建具有角色的 IPrincipal 对象,并将其存储到 HttpContext.User 中。在随后执行 URL 授权时,将根据 IPrincipal 对象中保存的用户和角色(无论以何种方式检索它们)执行授权。
429
430
431
432_**URL 授权示例** _
433下面的列表列出了一些典型 URL 授权示例的语法:
434
435 * 拒绝匿名帐户的访问
436<deny users="?"></deny>
437
438 * 拒绝所有用户的访问
439<deny users="*"></deny>
440
441 * 拒绝 Manager 角色的访问
442<deny roles="Manager"></deny>
443
444 * 表单身份验证示例
445<configuration>
446<system.web>
447<authentication mode="Forms">
448<forms loginurl="login.aspx" name=".ASPXUSERDEMO" protection="All" timeout="60"></forms>
449</authentication>
450<authorization>
451<deny users="[email protected]"></deny>
452<deny users="?"></deny>
453</authorization>
454</system.web>
455</configuration>
456
457
458
459**_
460更多信息 _ **
461<authorization> 元素可用于存储在 HttpContext.User 和 HttpContext.Request.RequestType 中的当前 IPrincipal 对象。
462
463**_保护资源_ **
464
465> 1\. 使用 Windows ACL 保护资源,包括文件、文件夹和注册表项。
466> 如果不使用模拟,则应用程序需要访问的任何资源的 ACL 必须给 ASP.NET 进程帐户至少授予读取访问权限。
467> 如果使用模拟,文件和注册表项的 ACL 必须给已验证用户(或匿名 Internet 用户帐户,如果匿名身份验证生效的话)至少授予读取访问权限。
468>
469> 2\. 保护 Web.config 和 Machine.config:
470>
471>> **使用正确的 ACL** 如果 ASP.NET 使用模拟,则模拟的标识需要读取访问权限。否则,ASP.NET 进程标识需要读取访问权限。对 Web.config 和 Machine.config 使用以下 ACL。
472> 系统:完全控制
473> 管理员:完全控制
474> 进程标识或模拟的标识:读取
475> 如果没有模拟匿名 Internet 用户帐户 (IUSR_MACHINE),则应该拒绝该帐户的访问。
476>
477> 注意:如果将应用程序映射到 UNC 共享,则 UNC 标识也需要读取配置文件的访问权限。
478>>
479>> **删除不需要的 HTTP 模块** Machine.config 包含一组默认的 HTTP 模块(在 <httpmodules> 元素内)。它们包括:
480>>
481>> * WindowsAuthenticationModule
482>> * FormsAuthenticationModule
483>> * PassportAuthenticationModule
484>> * UrlAuthorizationModule
485>> * FileAuthorizationModule
486>> * OutputCacheModule
487>> * SessionStateModule
488>>
489
490>>
491>> 如果应用程序没有使用特定的模块,请将其删除,以免将来在应用程序中出现与该模块有关的任何潜在安全问题。
492>
493> 3\. (可选)将 <location> 元素与 allowOverride="false" 属性一起使用以锁定配置设置(如下所示)。
494
495_**锁定配置设置** _
496
497> 配置设置是分层的。子目录中的 Web.config 文件设置覆盖父目录中的 Web.config 设置。另外,Web.config 设置覆盖 Machine.config 设置。
498> 通过将 <location> 元素与 allowOverride 属性一起使用,可以锁定配置设置以防止它们被低级别的设置覆盖。例如:
499>
500> <location allowoverride="false" path="somepath"></location>
501> . . . arbitrary configuration settings . . .
502> </location>
503>
504> 请注意,路径可以指 Web 站点或虚拟目录,并且它适用于指定的目录和所有子目录。如果将 allowOverride 设置为 false,则可以防止任何低级别的配置文件覆盖 <location> 元素中指定的设置。锁定配置设置的功能适用于所有设置类型,而不是仅限于安全设置(如身份验证模式)。
505
506**_禁止下载文件_ **
507
508> 可以使用 HttpForbiddenHandler 类禁止通过 Web 下载某些文件类型。该类由 ASP.NET 在内部使用以禁止下载某些系统级别文件(例如,包括 web.config 在内的配置文件)。有关可用这种方法进行限制的文件类型的完整列表,请参见 machine.config 中的 <httphandlers> 节。
509> 对于应用程序在内部使用但不能进行下载的文件,应考虑使用 HttpForbiddenHandler。
510>
511> 注意:还必须使用 Windows ACL 来保护文件,控制哪些用户在登录到 Web 服务器上时可以访问这些文件。
512>
513> **使用 HttpForbiddenHandler 禁止下载特定的文件类型**
514>
515> * 在 IIS 中为指定的文件类型创建应用程序映射,以便将其映射到 Aspnet_isapi.dll。
516>
517> a. 在任务栏上,依次单击“开始”按钮、“程序”、“管理工具”,然后选择“Internet 信息服务”。
518> b. 选择应用程序的虚拟目录,右击,然后单击“属性”。
519> c. 选择“应用程序设置”,然后单击“配置”。
520> d. 单击“添加”以创建新的应用程序映射。
521> e. 单击“浏览”,然后选择 c:\winnt\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll。
522> f. 在“扩展名”字段中输入要禁止下载的文件类型的扩展名(例如 .abc)。
523> g. 确保选中“所有谓词”和“脚本引擎”,并且没有选中“检查文件是否存在”。
524> h. 单击“确定”关闭“添加/编辑应用程序扩展映射”对话框。
525> i 单击“确定”关闭“应用程序配置”对话框,然后再单击“确定”关闭“属性”对话框。
526>
527>
528>
529> * 在 Web.config 中,为指定的文件类型添加 <httphandler> 映射。
530> 下面显示了一个 .abc 文件类型的示例。
531>
532> <httphandlers>
533> <add path="*.abc" verb="*"> type="System.Web.HttpForbiddenHandler"/>
534> </add></httphandlers>
535>
536
537
538_**安全通信** _
539结合使用 SSL 和 Internet 协议安全 (IPSec) 以保护通信链路。
540
541_**详细信息** _
542
543 * 有关使用 SSL 保护数据库服务器链路的信息,请参见“如何做:使用 SSL 来确保与 SQL Server 2000 安全通信”。
544 * 有关在两台计算机之间使用 IPSec 的信息,请参见“如何做:使用 IPSec 以便在两台服务器之间安全通信”。
545
546
547
548**
549编程安全性 **
550
551在确定 Web 应用程序可配置的安全设置后,您需要以编程方式进一步改进和优化应用程序的授权策略。这包括在程序集中使用说明性的 .NET 属性,以及在代码中执行命令性的授权检查。
552本节重点介绍在 ASP.NET Web 应用程序中执行授权所需的主要编程步骤。
553
554> _**授权模式** _
555> 下面总结了在 Web 应用程序中对用户进行授权的基本模式:
556> 1\. 检索凭据
557> 2\. 验证凭据
558> 3\. 将用户放到角色中
559> 4\. 创建一个 IPrincipal 对象
560> 5\. 将 IPrincipal 对象放到当前的 HTTP 上下文中
561> 6\. 基于用户标识/角色成员身份进行授权
562> 重要信息:如果配置了 Windows 身份验证,则 ASP.NET 自动执行步骤 1 到 5。对于其他身份验证机制(表单、Passport 和自定义方法),您必须编写代码以执行这些步骤(如下所示)。
563>
564> **_检索凭据_ **
565> 首先,必须从用户检索一组凭据(用户名和密码)。如果应用程序没有使用 Windows 身份验证,则需要确保使用 SSL 在网络上正确保护明文凭据。
566>
567> _**验证凭据** _
568> 如果配置了 Windows 身份验证,则操作系统的基本服务就会自动对凭据进行验证。
569> 如果使用其他身份验证机制,则必须编写代码以根据数据存储(如 SQL Server 数据库或 Active Directory)对凭据进行验证。
570> 有关如何将用户凭据安全地存储在 SQL Server 数据库中的详细信息,请参见第 12 章“数据访问安全性”中的“对数据库进行用户身份验证”。
571> **_
572> 将用户放到角色中 _ **
573> 用户数据存储还应包含每个用户的角色列表。必须编写代码以检索已验证用户的角色列表。
574>
575> _**创建一个 IPrincipal 对象** _
576> 授权是针对已验证用户进行的,这些用户的标识和角色列表保存在 IPrincipal 对象中(该对象在当前 Web 请求的上下文中传递)。
577> 如果配置了 Windows 身份验证,则 ASP.NET 自动构造 WindowsPrincipal 对象。该对象包含已验证用户的标识以及角色列表(它等同于用户所属的 Windows 组列表)。
578> 如果使用的是表单、Passport 或自定义身份验证,则必须在 Global.asax 的 Application_AuthenticateRequest 事件处理程序中编写代码以创建 IPrincipal 对象。GenericPrincipal 类是由 .NET 框架提供的,在大多数情况下应该使用该类。
579>
580> _**将 IPrincipal 对象放到当前的 HTTP 上下文中** _
581> 将 IPrincipal 对象附加到当前的 HTTP 上下文中(使用 HttpContext.User 变量)。如果使用 Windows 身份验证,则 ASP.NET 自动完成此任务。否则,您必须手动附加该对象。
582>
583> _**基于用户标识和/或角色成员身份进行授权** _
584> 如果应用程序需要更细分的授权逻辑,请在代码中以声明方式(获取类或方法级授权)或命令性方式使用 .NET 角色。
585> 可以使用说明性或命令性用户权限要求(使用 PrincipalPermission 类),也可以通过调用 IPrincipal.IsInRole() 方法执行明确的角色检查。
586> 下面的示例采用 Windows 身份验证并显示了说明性主体权限要求。仅当已验证用户是 Manager Windows 组的成员时,才执行该属性后面的方法。如果调用方不是该组的成员,就会发生 SecurityException。
587>
588> [PrincipalPermission(SecurityAction.Demand,
589> Role=@"DomainName\Manager")]
590> public void SomeMethod()
591> {
592> }
593>
594> 下面的示例显示了代码中的明确角色检查。该示例采用 Windows 身份验证。如果使用非 Windows 身份验证机制,则代码基本上是一样的。只是将 User 对象转换为 GenericPrincipal 对象,而不是 WindowsPrincipal 对象。
595>
596> // Extract the authenticated user from the current HTTP context.
597> // The User variable is equivalent to HttpContext.Current.User if you are using // an .aspx or .asmx page
598> WindowsPrincipal authenticatedUser = User as WindowsPrincipal;
599> if (null != authenticatedUser)
600> {
601> // Note: To retrieve the authenticated user's username, use the
602> // following line of code
603> // string username = authenticatedUser.Identity.Name;
604>
605> // Perform a role check
606> if (authenticatedUser.IsInRole(@"DomainName\Manager") )
607> {
608> // User is authorized to perform manager functionality
609> }
610> }
611> else
612> {
613> // User is not authorized to perform manager functionality
614> }
615>
616>> **更多信息**
617> 有关以上表单身份验证模式的实际实现,请参见本章后面的“表单身份验证”部分。
618>
619> _**创建自定义 IPrincipal 类** _
620> 当使用非 Windows 身份验证机制时,大多数情况下应使用.NET 框架提供的 GenericPrincipal 类。它使用 IPrincipal.IsInRole 方法提供角色检查。
621> 有时,您可能需要实现您自己的 IPrincipal 类。实现您自己的 IPrincipal 类的原因包括:
622>
623> * 您想扩展角色检查的功能。您可能需要一些方法来使您能够检查某一特定用户是否是一个多角色成员。例如:CustomPrincipal.IsInAllRoles( "Role", "Role2", "Role3" )
624> CustomPrincipal.IsInAnyRole( "Role1", "Role2", "Role3" )
625>
626> * 您可能需要实现一个额外的方法或属性,以数组形式返回角色列表。例如:string[] roles = CustomPrincipal.Roles;
627>
628> * 您想让应用程序强制实施角色分级逻辑。例如,高级管理员被认为在层次结构中高于普通管理员。可以用类似下面所示的方法进行测试。
629> CustomPrincipal.IsInHigherRole("Manager");
630> CustomPrincipal.IsInLowerRole("Manager");
631>
632> * 您可能需要实现惰性的角色列表初始化。例如,只有在需要进行角色检查时,才能动态加载角色列表。
633>
634> * 您可能需要实现 IIdentity 接口以使用 X509ClientCertificate 标识的用户。例如:
635> CustomIdentity id = CustomPrincipal.Identity;
636> X509ClientCertificate cert = id.ClientCertificate;
637>
638> **更多信息**
639> 有关创建您自己的 IPrincipal 类的详细信息,请参见本指南“参考”部分的“如何做:实现自定义 IPrincipal 类”。
640>
641>
642
643
644** Windows 身份验证 **
645
646> 如果应用程序用户使用可由服务器进行身份验证的 Windows 帐户(例如,在 Intranet 方案中),请使用 Windows 身份验证。
647> 如果将 ASP.NET 配置为使用 Windows 身份验证,则 IIS 使用配置的 IIS 身份验证机制执行用户身份验证。图 8.4 中显示了这种情况。
648> 
649> 图 8.4 _ASP.NET Windows 身份验证使用 IIS 验证调用方的身份_
650>
651> 已验证调用方(如果将 IIS 配置为使用匿名身份验证,则它可能是匿名 Internet 用户帐户)的访问令牌可供 ASP.NET 应用程序使用。请注意以下方面:
652>
653> * 这将允许 ASP.NET FileAuthorizationModule 使用原调用方的访问令牌,对请求的 ASP.NET 文件执行访问检查。
654> 重要信息:ASP.NET 文件授权只对映射到 Aspnet_isapi.dll 的文件类型执行访问检查。
655>
656> * 文件授权不要求使用模拟。如果启用了模拟,则应用程序执行的所有资源访问均使用被模拟的调用方的标识。在这种情况下,请确保附加到资源上的 ACL 包含一个访问控制项 (ACE),它可给原调用方标识至少授予读取访问权限。
657>
658
659>
660> **_标识已验证身份的用户_ **
661> ASP.NET 将 WindowsPrincipal 对象与当前的 Web 请求关联起来。这包含已验证身份的 Windows 用户的标识以及该用户所属的角色列表。在 Windows 身份验证中,角色列表是由用户所属的 Windows 组集组成的。
662> 以下代码显示如何获取已验证 Windows 用户的标识,以及如何执行简单的角色授权测试。
663>
664> WindowsPrincipal user = User as WindowsPrincipal;
665> if (null != user)
666> {
667> string username = user.Identity.Name;
668> // Perform a role check
669> if ( user.IsInRole(@"DomainName\Manager") )
670> {
671> // User is authorized to perform manager functionality
672> }
673> }
674> else
675> {
676> // Throw security exception as we don't have a WindowsPrincipal
677> }
678
679**
680表单身份验证 **
681
682当使用表单份验证时,如果未验证身份的用户试图访问受保护的文件或资源(其中,URL 授权拒绝用户访问),该用户所触发的事件顺序如图 8.5 所示。
683
684图 8.5 _表单身份验证的事件顺序_
685
686下面说明了图 8.5 中显示的事件顺序:
687
688 1. 用户发出一个针对 Default.aspx 的 Web 请求。
689由于启用了匿名访问,因此 IIS 允许进行此类请求。ASP.NET 检查 <authorization> 元素并查找 <deny users="?”/"> 元素。
690 2. 将用户重定向到由 <forms> 元素的 LoginUrl 属性指定的登录页 (Login.aspx)。
691 3. 用户提供凭据并提交登录表单。
692 4. 根据数据存储(SQL Server 或 Active Directory)验证凭据,并检索角色(可选)。如果要使用基于角色的授权,则必须检索角色列表。
693 5. 使用 FormsAuthenticationTicket 创建一个 Cookie 并将其发回到客户端。将角色存储到票中(可选)。通过在票中存储角色列表,可以避免为相同用户的每个后续 Web 请求访问数据库重新检索列表。
694 6. 客户端重定向将用户重定向到原请求页 (Default.aspx)。
695 7. 在 Application_AuthenticateRequest 事件处理程序(在 Global.asax 中)中,使用票创建 IPrincipal 对象并将其存储在 HttpContext.User 中。
696ASP.NET 检查 <authorization> 元素并查找 <deny users="?”/"> 元素。但是,此时对用户进行身份验证。
697ASP.NET 检查 <authorization> 元素以确保用户在 <allow> 元素中。
698给用户授予访问 Default.aspx 的权限。
699
700
701
702_**表单身份验证的开发步骤** _
703以下列表重点介绍了实现表单身份验证时必须执行的主要步骤:
7041\. 将 IIS 配置为使用匿名访问。
7052\. 将 ASP.NET 配置为使用表单身份验证。
7063\. 创建登录 Web 表单并验证提供的凭据。
7074\. 从自定义数据存储中检索角色列表。
7085\. 创建表单身份验证票(在票中存储角色)。
7096\. 创建一个 IPrincipal 对象。
7107\. 将 IPrincipal 对象放到当前的 HTTP 上下文中。
7118\. 基于用户名/角色成员身份对用户进行授权。
712**_
713将 IIS 配置为使用匿名访问 _ **
714必须在 IIS 中将应用程序的虚拟目录配置为使用匿名访问。
715
716> 将 IIS 配置为使用匿名访问
717> 1\. 启动 Internet 信息服务管理工具。
718> 2\. 选择应用程序的虚拟目录,右击,然后单击“属性”。
719> 3\. 单击“目录安全性”。
720> 4\. 在“匿名访问和验证控件”组中,单击“编辑”。
721> 5\. 选择“匿名访问”。
722
723_**将 ASP.NET 配置为使用表单身份验证** _
724下面显示了一个配置示例。
725<authentication mode="Forms">
726<forms loginurl="login.aspx" name="MyAppFormsAuth" path="/" protection="Encryption" timeout="20">
727</forms>
728</authentication>
729
730**_创建登录 Web 表单并验证提供的凭据_ **
731根据 SQL Server 数据库或 Active Directory 验证凭据。
732
733**_更多信息_ **
734
735 * 请参见本指南“参考”部分的“如何做:将表单身份验证用于 SQL Server 2000”。
736 * 请参见本指南“参考”部分的“如何做:将表单身份验证用于 Active Directory”。
737
738
739
740**_从自定义数据存储中检索角色列表_ **
741从 SQL Server 数据库表中获取角色,或从 Active Directory 内配置的组/分发列表中获取角色。有关详细信息,请参考前面的资源。
742
743**_创建表单身份验证票_ **
744在票中存储检索到的角色。下面的代码阐释了此过程。
745
746// This event handler executes when the user clicks the Logon button
747// having supplied a set of credentials
748private void Logon_Click(object sender, System.EventArgs e)
749{
750// Validate credentials against either a SQL Server database
751// or Active Directory
752bool isAuthenticated = IsAuthenticated( txtUserName.Text,
753txtPassword.Text );
754if (isAuthenticated == true )
755{
756// Retrieve the set of roles for this user from the SQL Server
757// database or Active Directory.The roles are returned as a
758// string that contains pipe separated role names
759// for example "Manager|Employee|Sales|"
760// This makes it easy to store them in the authentication ticket
761
762string roles = RetrieveRoles( txtUserName.Text, txtPassword.Text );
763
764// Create the authentication ticket and store the roles in the
765// custom UserData property of the authentication ticket
766FormsAuthenticationTicket authTicket = new
767FormsAuthenticationTicket(
7681, // version
769txtUserName.Text, // user name
770DateTime.Now, // creation
771DateTime.Now.AddMinutes(20),// Expiration
772false, // Persistent
773roles ); // User data
774// Encrypt the ticket.
775string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
776// Create a cookie and add the encrypted ticket to the
777// cookie as data.
778HttpCookie authCookie =
779new HttpCookie(FormsAuthentication.FormsCookieName,
780encryptedTicket);
781
782// Add the cookie to the outgoing cookies collection.
783Response.Cookies.Add(authCookie);
784// Redirect the user to the originally requested page
785Response.Redirect( FormsAuthentication.GetRedirectUrl(
786txtUserName.Text,
787false));
788}
789}
790
791**_创建一个 IPrincipal 对象_ **
792在 Global.asax 内的 Application_AuthenticationRequest 事件处理程序中创建 IPrincipal 对象。除非您需要基于角色的扩展功能,否则,请使用 GenericPrincipal 类。在这种情况下,创建一个实现 IPrincipal 的自定义类。
793
794**_将 IPrincipal 对象放到当前的 HTTP 上下文中_ **
795GenericPrincipal 对象的创建过程如下所示。
796
797protected void Application_AuthenticateRequest(Object sender, EventArgs e)
798{
799// Extract the forms authentication cookie
800string cookieName = FormsAuthentication.FormsCookieName;
801HttpCookie authCookie = Context.Request.Cookies[cookieName];
802if(null == authCookie)
803{
804// There is no authentication cookie.
805return;
806}
807FormsAuthenticationTicket authTicket = null;
808try
809{
810authTicket = FormsAuthentication.Decrypt(authCookie.Value);
811}
812catch (Exception ex)
813{
814// Log exception details (omitted for simplicity)
815return;
816}
817if (null == authTicket)
818{
819// Cookie failed to decrypt.
820return;
821}
822// When the ticket was created, the UserData property was assigned a
823// pipe delimited string of role names.
824string[] roles = authTicket.UserData.Split(new char[]{'|'});
825
826// Create an Identity object
827FormsIdentity id = new FormsIdentity( authTicket );
828// This principal will flow throughout the request.
829GenericPrincipal principal = new GenericPrincipal(id, roles);
830// Attach the new principal object to the current HttpContext object
831Context.User = principal;
832}
833
834**_基于用户名或角色成员身份对用户进行授权_ **
835使用说明性的主体权限要求来限制对方法的访问。使用命令性主体权限要求和/或明确角色检查 (IPrincipal.IsInRole) 在方法中执行细分的授权。
836
837**_表单实现原则_ **
838
839 * 当使用 HTML 表单捕获凭据时,请使用 SSL。
840无论何时通过网络发送凭据或身份验证 Cookie,除了对登录页使用 SSL 外,还应该对其他页使用 SSL。这样,可以减轻与 Cookie 重播攻击相关的威胁。
841 * 根据自定义数据存储验证用户的身份。请使用 SQL Server 或 Active Directory。
842 * 从自定义数据存储中检索角色列表,并在 FormsAuthenticationTicket 类的 UserData 属性中存储分隔的角色列表。这样,不必为每个 Web 请求重复访问数据存储,从而提高了性能;而且还免去了在身份验证 Cookie 中存储用户凭据的麻烦。
843 * 如果角色列表很大并且有超过 Cookie 大小限制的危险,请在 ASP.NET 缓存对象或数据库中存储角色的详细信息,并在每个后续请求中检索这些信息。
844 * 对于初始身份验证后的每个请求:
845 * 在 Application_AuthenticateRequest 事件处理程序中,从票中检索角色。
846 * 创建一个 IPrincipal 对象并将其存储在 HTTP 上下文 (HttpContext.User) 中。.NET 框架还将其与当前 .NET 线程 (Thread.CurrentPrincipal) 关联起来。
847 * 除非您有特殊的原因需要创建自定义的 IPrincipal 实现(例如,支持基于角色的增强操作),否则请使用 GenericPrincipal 类。
848 * 使用两种 Cookie:一种用于个性化,另一种用于安全的身份验证和授权。将个性化 Cookie 作为永久性的 Cookie(确保它不包含允许请求执行受限操作的信息;例如在站点中的安全部分下订单)。
849 * 对于每个 Web 应用程序,请使用单独的 Cookie 名称(使用 <forms> 元素的 Forms 属性)和路径。如果针对某个应用程序验证了用户的身份,这可确保在使用同一 Web 服务器承载的第二个应用程序时,不会将这些用户作为已验证的用户处理。
850 * 确保在客户端浏览器中启用 Cookie。对于不需要 Cookie 的表单身份验证方法,请参见本章后面的“无 Cookie 表单身份验证”。
851
852**更多信息**
853
854 * 请参见本指南“参考”部分的“如何做:将表单身份验证用于 SQL Server 2000”。
855 * 请参见本指南“参考”部分的“如何做:将表单身份验证用于 Active Directory”。
856 * 请参见本指南“参考”部分的“如何做:将表单身份验证用于 GenericPrincipal 对象”。
857
858
859
860**_承载多个使用表单身份验证的应用程序_ **
861如果在同一 Web 服务器上承载多个使用表单身份验证的 Web 应用程序,在某一应用程序中已验证身份的用户可以请求另一个应用程序,而无需重定向到该应用程序的登录页。第二个应用程序中的 URL 授权规则可能会拒绝该用户的访问,而不会提供使用登录表单提供登录凭据的机会。
862仅在以下情况下发生这种情况:多个应用程序的 <forms> 元素的名称和路径属性是相同的,而且每个应用程序在 Web.config 中使用相同的 <machinekey> 元素。
863
864> **更多信息**
865> 有关此问题的详细信息以及解决方法,请参见以下知识库文章:
866>
867> * Q313116“PRB: Forms Authentication Requests Are Not Directed to loginUrl Page(PRB:没有将表单身份验证请求定向到 loginUrl 页)”
868> * Q310415“PRB: Mobile Forms Authentication and Different Web Applications(PRB:移动表单身份验证和各种 Web 应用程序)”
869>
870
871
872_**无 Cookie 表单身份验证** _
873如果您需要无 Cookie 表单身份验证解决方案,请考虑使用 Microsoft Mobile Internet Toolkit 所使用的方法。移动表单身份验证建立在表单身份验证之上,但使用查询字符串来传递身份验证票而不是使用 Cookie 。
874
875> **更多信息**
876> 有关移动表单身份验证的详细信息,请参见 Microsoft 知识库文章 Q311568“INFO: How To Use Mobile Forms Authentication with Microsoft Mobile Internet Toolkit(INFO:如何将移动表单身份验证用于 Microsoft Mobile Internet Toolkit)”。
877
878**
879Passport 身份验证 **
880
881> 如果应用程序用户使用 Passport 帐户,而且您要在其他支持 Passport 的站点上实现单次登录解决方案,则应使用 Passport 身份验证。
882> 当将 ASP.NET 配置为使用 Passport 身份验证时,就会提示用户登录并将该用户重定向到 Passport 站点。在成功验证了凭据后,就会将用户重定向回您的站点。
883>
884> _**将 ASP.NET 配置为使用 Passport 身份验证** _
885> 要将 ASP.NET 配置为使用 Passport 身份验证,请使用以下 Web.config 设置。
886>
887> <authentication mode="Passport">
888> <passport redirecturl="internal"></passport>
889> </authentication>
890> <authorization>
891> <deny users="?"></deny>
892> <allow users="*"></allow>
893> </authorization>
894>
895> **_将 Passport 标识映射为 Global.asax 中的角色_ **
896> 要将 Passport 标识映射为角色,按如下所示在 Global.asax 中实现 PassportAuthentication_OnAuthentication 事件处理程序。
897>
898> void PassportAuthentication_OnAuthenticate(Object sender,
899> PassportAuthenticationEventArgs e)
900> {
901> if(e.Identity.Name == "0000000000000001")
902> {
903> string[] roles = new String[]{"Developer", "Admin", "Tester"};
904> Context.User = new GenericPrincipal(e.Identity, roles);
905> }
906> }
907>
908> **_测试角色成员身份_ **
909> 以下代码片段显示了如何在 aspx 页中检索已验证身份的 Passport 标识和检查角色成员身份。
910>
911> PassportIdentity passportId = Context.User.Identity as PassportIdentity;
912> if (null == passportId)
913> {
914> Response.Write("Not a PassportIdentity<br/>");
915> return;
916> }
917> Response.Write("IsInRole: Develeoper?" + Context.User.IsInRole("Developer"));
918
919**
920自定义身份验证 **
921
922如果 .NET 框架提供的身份验证模块均不能满足您的确切身份验证需要,则可以使用自定义身份验证并实现您自己的身份验证机制。例如,您的公司可能已经制订了一个可由其他应用程序广泛使用的自定义身份验证策略。
923要在 ASP.NET 中实现自定义身份验证,请执行下列操作:
924
925 * 按如下所示在 Web.config 中配置身份验证模式。这将通知 ASP.NET 不要调用它的任何内置身份验证模块。
926<authentication mode="None"></authentication>
927
928 * 创建实现 System.Web.IHttpModule 接口的类以创建自定义的 HTTP 模块。此模块应该挂钩到 HttpApplication.AuthenticateRequest 事件中,并在要求身份验证时对每个应用程序请求提供要调用的委派。
929身份验证模块必须:
930 * 从调用方获取凭据。
931 * 根据存储验证凭据。
932 * 创建一个 IPrincipal 对象并将其存储在 HttpContext.User 中。
933 * 创建并保护已验证身份的令牌,并将其发回到用户(通常在查询字符串、Cookie 或隐藏的表单字段中)。
934 * 在后续请求中获取身份验证令牌,对它进行验证,然后重新分发。
935
936**更多信息**
937有关如何实现自定义 HTTP 模块的详细信息,请参见 Microsoft 知识库文章 Q307996“HOW TO: Create an ASP.NET HTTP Module Us</machinekey></forms></forms></allow></authorization></deny></authorization></forms></deny></authorization></httphandler></httphandlers></location></location></httpmodules></authorization></authorization></authorization></authorization></identity></identity></identity></authorization></authorization>