您的位置:首页 > 编程语言 > ASP

在 ASP.NET 中使用代码访问安全

2005-05-12 07:32 549 查看
发布日期: 12/15/2004 | 更新日期: 12/15/2004


查看全部的安全性指南主题
Microsoft Corporation


本单元概要

代码访问安全是一个资源约束模型,使管理员可确定特定代码是否和如何访问指定的资源并执行其他特权操作。本单元的重点放在 ASP.NET 代码访问安全策略配置上,说明如何克服开发部分信任 Web 应用程序时可能遇到的一些主要障碍。
本单元详细阐述了代码访问安全的实际要素,您将学到如何开发中度信任的 Web 应用程序,在获益于代码访问安全提供的安全保护的同时,仍然能够使用要求完全信任的组件。
本单元还包含有关如何创建自定义 ASP.NET 信任策略的信息,并包含两个非常有价值的列表:
适用 APTCA (AllowPartiallyTrustedCallersAttribute) 的系统程序集。
默认的 ASP.NET 策略权限和信任级。它指定了每个 ASP.NET 信任级都施加了哪些关键限制。


返回页首

目标

通过本单元能够:
了解 ASP.NET 策略文件的工作原理以及如何创建自定义策略。
开发部分信任 Web 应用程序。
从部分信任 Web 应用程序使用 OLE DB、事件日志、Web 服务和注册表。
用沙箱保护特权代码。
了解何时用沙箱保护和何时自定义现有的 ASP.NET 信任策略。


返回页首

应用范围

本单元适用于下列产品和技术:
Microsoft® Windows® 2000 Server 和 Microsoft Windows Server® 2003 操作系统
Microsoft .NET Framework 1.1 和 ASP.NET 1.1


返回页首

如何使用本单元

本单元并未涵盖代码访问安全的基础知识。我们假设读者已经具备一些预备知识,虽然重要的概念在适当的时候会进行重述。有关代码访问安全工作原理的更多信息,请参阅“代码访问安全实践”单元。
使用本单元可以学会如何使用代码访问安全锁定 Web 应用程序,并针对潜在的攻击加固服务器。
如果您管理着共享宿主环境,或者为一个 Internet 服务提供商 (ISP) 工作,要在同一台 Web 服务器上运行多个来自不同公司的应用程序,就可以使用代码访问安全:
使应用程序互相独立
例如,代码访问安全可以用来确保 Web 应用程序无法写另一个 Web 应用程序的目录。
将应用程序与系统资源独立开来
例如,代码访问安全可以限制对文件系统、注册表、事件日志、网络资源和其他系统资源的访问。
还要注意的是,Windows Server 2003 和 Internet 信息服务 (IIS) 6.0 为 Web 应用程序提供了进一步的进程独立。进程独立结合代码访问安全是应用程序独立的推荐模型。
有关更多信息,请参阅单元“寄宿多个 ASP.NET 应用程序”。
本页内容


本单元概要


目标


应用范围


如何使用本单元


概述


资源访问


完全信任和部分信任


在 ASP.NET 中配置代码访问安全


ASP.NET 策略文件


ASP.NET 策略


开发部分信任 Web 应用程序


信任级


部分信任 Web 应用程序的处理办法


自定义策略


用沙箱保护特权代码


确定采用哪种办法


中度信任


中度信任的限制


小结


其他资源


返回页首

概述

传统的基于用户的安全,比如操作系统提供的安全,需要根据用户标识对各种资源的访问进行授权。
在 Microsoft .NET Framework 1.1 版中,管理员可以为 ASP.NET Web 应用程序和 Web 服务(可以由多个程序集组成)配置策略。它们还可授予代码访问安全权限,以允许应用程序访问特定的资源类型以及执行特定的特权操作。
例如:
一个管理员可能决定应该不对从 Internet 下载的代码授予访问任何资源的权限,而某个特定的公司开发的 Web 应用程序代码应该获得更高的信任度,例如,允许访问文件系统、事件日志和 Microsoft SQL Server 数据库。
本地管理员启动的程序在本机上是没有限制的。糟糕的是,如果管理员的标识被哄骗,而且恶意用户能够使用管理员的安全上下文执行代码,那么恶意用户同样没有限制。
这些领域中代码访问安全非常重要,因为它可以根据代码本身而不是运行代码的用户提供更多的限制和安全。
使用 .NET Framework 1.0 版构建的 Web 应用程序和 Web 服务总是以无限的代码访问权限运行的。这是不可配置的。


返回页首

资源访问

所有来自 ASP.NET 应用程序和托管代码的资源访问一般而言要受以下两个安全层次的限制:
代码访问安全。这一安全层将验证当前调用堆栈中的所有代码(一直引向并包括资源访问代码)是否已经得到访问资源的授权。管理员可以使用代码访问安全策略将权限授予程序集。权限准确确定了程序集可以访问哪些资源类型。可以访问的不同资源类型对应于许多权限类型。这些类型包含文件系统、注册表、事件日志、目录服务、Microsoft SQL Server_、OLE DB 数据源和网络资源。
有关代码访问权限的完整列表,请参阅“代码访问安全实践”单元。
操作系统/平台安全。这一安全层将验证请求方线程的安全上下文是否可以访问资源。如果线程正在模拟,则使用线程模拟标记。否则,则使用进程标记并与同资源相关联的访问控制列表 (ACL) 比较,以确定所请求的操作是否可以执行,所请求的资源是否可以访问。
资源如果要成功地进行访问,必须通过以上两种检查。.NET Framework 类公开的所有资源类型都是用代码访问权限保护的。图 1 说明了 Web 应用程序访问的一组常见的资源类型,以及访问想要成功必需的相关代码访问权限。



图 1. 从 ASP.NET Web 应用程序访问的常见资源类型和相关权限类型

返回页首

完全信任和部分信任

默认时,Web 应用程序以完全信任运行。完全信任应用程序将被代码访问安全策略授予无限的代码访问权限。这些权限包括内置的系统权限和自定义权限。这意味着代码访问安全将不会阻止应用程序访问任何得到保护的资源类型,如图 1 所示。资源访问的成败完全取决于操作系统级安全。以完全信任运行的 Web 应用程序包括所有用 .NET Framework 1.0 版构建的 ASP.NET 应用程序。默认时,.NET Framework 1.1 版应用程序是以完全信任运行的,但信任级可以配置为使用 <trust> 元素,这一点在本单元后面将进行讲述。
如果一个应用程序被配置为“Full”之外的某个信任级,就称它为部分信任应用程序。部分信任应用程序的权限都是受限的,该权限将限制它们访问得到保护的资源的能力。
重要说明 用 .NET Framework 1.0 版构建的 Web 应用程序始终是以完全信任运行的,因为 System.Web 中的类型要求完全信任调用方。


返回页首

在 ASP.NET 中配置代码访问安全

默认时,Web 应用程序以完全信任运行,具有无限权限。在 ASP.NET 中要修改代码访问安全的信任级,必须在 Machine.config 或者 Web.config 中设置一个开关,将应用程序配置为部分信任应用程序。

配置信任级

Machine.config 中的 <trust> 元素控制着是否为 Web 应用程序启用代码访问安全。打开 Machine.config,搜索“”,可以看到以下内容。
<system.web>
<!-- level="[Full|High|Medium|Low|Minimal]" -->
<trust level="Full" originUrl=""/>
</system.web>
当信任级设置为“Full”时,实际上将禁用代码访问安全,因为权限要求并不阻止访问资源的尝试。这是 .NET Framework 1.0 版上构建的 ASP.NET Web 应用程序的唯一选择。从“Full”到“Minimal”,每个级别都会删去更多权限,从而进一步限制应用程序访问得到保护的资源和执行特权操作的能力。每个级别都提供了更大程度的应用程序独立。表 1 说明了预定义的信任级,并指出了与前一级别相比较的主要限制。
表 1 ASP.NET 信任级所施加的限制
ASP.NET 信任级主要限制
Full无限权限。应用程序可以访问任何受操作系统安全限制的资源。支持所有特权操作。
High不能调用非托管代码
不能调用服务组件
不能写事件日志
不能访问 Microsoft 消息队列
不能访问 OLE DB 数据源
Medium除上述之外,文件访问仅限于当前应用程序目录,注册表访问是不允许的。
Low除上述之外,应用程序不能连接 SQL Server,代码无法调用 CodeAccessPermission.Assert(即不能断言安全权限)。
Minimal只有执行权限。

锁定信任级

如果 Web 服务器管理员想使用代码访问安全以确保应用程序独立,并限制对系统级资源的访问,管理员必须能够在机器级定义安全策略,防止单独的应用程序将其改写。
应用程序服务提供商或者负责在同一服务器上运行多个 Web 应用程序的任何人,应该锁定所有 Web 应用程序的信任级。为此,将 Machine.config 中的 <trust> 元素装入 <location> 标记,并将 allowOverride 属性设置为 false,如下例所示。
<location allowOverride="false">
<system.web>
<!-- level="[Full|High|Medium|Low|Minimal]" -->
<trust level="Medium" originUrl=""/>
</system.web>
</location>
还可以使用 <location> 元素的一个 path 属性将某个配置应用于无法被改写的特定站点或者 Web 应用程序。有关 <location> 元素的更多信息,请参阅“保护 ASP.NET 应用程序的安全”单元。


返回页首

ASP.NET 策略文件

每个信任级都与一个 XML 策略文件对应,策略文件列出了每个信任级授予的权限集。策略文件位于以下目录:
%windir%/Microsoft.NET/Framework/{version}/CONFIG
信任级通过 Machine.config 中的 <trustLevel> 元素对应于各个策略文件,这些元素正好位于 <trust> 元素之上,如下例所示。
<location allowOverride="true">
<system.web>
<securityPolicy>
<trustLevel name="Full" policyFile="internal"/>
<trustLevel name="High" policyFile="web_hightrust.config"/>
<trustLevel name="Medium" policyFile="web_mediumtrust.config"/>
<trustLevel name="Low" policyFile="web_lowtrust.config"/>
<trustLevel name="Minimal" policyFile="web_minimaltrust.config"/>
</securityPolicy>
<!--  level="[Full|High|Medium|Low|Minimal]" -->
<trust level="Full" originUrl=""/>
</system.web>
</location>
完全信任级没有对应的策略文件。这是一个特例,只是表示所有权限的无限集。
ASP.NET 策略是完全可配置的。除了默认策略级之外,管理员可以创建自定义权限文件,并使用 <trust> 元素对其进行配置,这一点将在本单元后面叙述。与自定义级别相关的策略文件也必须用 Machine.config 中的 <trustLevel> 元素定义。


返回页首

ASP.NET 策略

代码访问安全策略是层次化的,可以在多个级别上进行管理。我们可以为企业级、机器级、用户级和应用程序域级创建策略。ASP.NET 代码访问安全策略是应用程序域级策略的一个例子。
一个 XML 配置文件中的设置为每个级都定义了策略。企业级、机器级和用户级策略可以用 Microsoft .NET Framework 配置工具进行配置,但是 ASP.NET 策略文件必须使用 XML 编辑器或者文本编辑器手工进行编辑。
单独的 ASP.NET 信任级策略文件可指出哪些权限可以被授予在某个特定的信任级配置的应用程序。授予一个 ASP.NET 应用程序的实际 权限是由所有 策略级(包括企业级、机器级、用户级和 ASP.NET(应用程序域)级策略)授予的权限的交集所确定的。
因为策略是从企业级向下计算到 ASP.NET 应用程序级的,权限只能不断删除。如果没有更高的级别首先授予权限,就无法在 ASP.NET 级添加权限。这种方式确保了企业级管理员始终具有最终决定权,在一个应用程序域中运行的恶意代码无法请求并被授予比管理员所配置的权限更多的权限。
有关策略计算的更多信息,请参阅“代码访问安全实践”单元。

ASP.NET 策略文件揭密

为了了解某个特定的信任级都定义了哪些权限,可以在记事本或者 XML 编辑器(更佳)中打开相应的策略文件,找到“ASP.NET”命名权限集。此权限集列出了为当前信任级的应用程序配置的权限。
还可以看到“FullTrust”和“Nothing”权限集。这些集合中不包含权限元素,因为“FullTrust”意味着所有权限,而“Nothing”意味着不包含权限。
以下代码片段显示了一个 ASP.NET 策略文件的主要元素:
<configuration>
<mscorlib>
<security>
<policy>
<PolicyLevel version="1">
<SecurityClasses>
... list of security classes, permission types,
and code group types ...
</SecurityClasses>
<NamedPermissionSets>
<PermissionSet Name="FullTrust" ... />
<PermissionSet Name="Nothing" .../>
<PermissionSet Name="ASP.NET" ...
... This is the interesting part ...
... List of individual permissions...
<IPermission
class="AspNetHostingPermission"
version="1"
Level="High" />
<IPermission
class="DnsPermission"
version="1"
Unrestricted="true" />
...Continued list of permissions...
</PermissionSet>
</PolicyLevel version="1">
</policy>
</security>
</mscorlib>
</configuration>
请注意 <IPermission> 元素定义的每个权限,它定义了权限类型名、版本和是否处于无限状态。

权限的状态和无限权限

许多权限都包含状态,状态可以用于微调权限指定的访问权限。状态准确确定了权限允许应用程序做些什么。例如,FileIOPermission 可能指定一个目录和一个访问类型(读取、写等等)。以下权限要求需要呼叫代码被授予访问 C:/SomeDir 目录的读取权限:
(new FileIOPermission(FileIOPermissionAccess.Read, @"C:/SomeDir")).Demand();
处于无限状态时,FileIOPermission 允许对文件系统任何区域进行任何类型的访问(当然,操作系统安全仍然适用)。以下权限要求需要呼叫代码被授予无限的 FileIOPermission 权限:
(new FileIOPermission(PermissionState.Unrestricted)).Demand();

ASP.NET 命名权限集

ASP.NET 策略文件包含一个“ASP.NET”命名权限集。该权限集定义了应用程序域策略授予相关应用程序的权限集。
ASP.NET 策略还引入了一个自定义的 AspNetHostingPermission,它有与默认级别之一相对应的一个相关 Level 属性。System.WebSystem.Web.Mobile 中所有公共类型都是用此权限的 Minimum 级要求进行保护的。这种降低风险策略的目的,是确保如果没有管理员的特定策略配置,Web 应用程序代码就无法用于其他部分信任环境。

替换参数

如果对某个ASP.NET 策略文件进行编辑,就可以注意到有些权限元素包含替换参数 ($AppDirUrl$、$CodeGen$ 和 $Gac$)。这些参数使您可将权限配置到属于 Web 应用程序但是要从不同位置加载的程序集。每个替换参数都会在安全策略计算时用实际值替换,这一过程会在第一次 Web 应用程序程序集加载时进行。Web 应用程序可能包括以下三种程序集类型:
生成时编译并部署在应用程序 bin 目录中的私有程序集。
重要说明 这种类型的程序集不能具有强名称。ASP.NET Web 应用程序所使用的具有强名称的程序集必须安装在全局程序集缓存中。由于多应用程序域辅助进程的内部工作方式,这一限制是必要的。
响应页请求所生成的动态编译程序集
从计算机的全局程序集缓存加载的共享程序集
这些程序集类型每个都有一个相关的替换参数,表 2 对此进行了总结。
表 2 ASP.NET 代码访问安全策略的替换参数
参数代表
$AppDirUrl$应用程序的虚拟根目录。允许权限应用于位于应用程序 bin 目录中的代码。
例如,如果虚拟目录对应于 C:/YourWebApp,那么 $AppDirUrl$ 就相当于 C:/YourWebApp。
$CodeGen$包含动态生成的程序集的目录(例如,.aspx 页的编译结果)。这可以逐个应用程序地配置,默认时是 %windir%/Microsoft.NET/Framework/{version}/Temporary ASP.NET Files。
$CodeGen$ 允许权限应用于动态生成的程序集。
$Gac$安装在计算机的全局程序集缓存 (GAC) (%windir%/assembly) 中的任何程序集。这允许权限被授予 Web 应用程序从 GAC 加载的具有强名称的程序集。


返回页首

开发部分信任 Web 应用程序

所谓部分信任 Web 应用程序就是没有完全信任但具有代码访问安全策略所确定的某个代码访问权限受限集的应用程序。因此,限制了部分信任应用程序访问得到保护的资源和执行其他特权操作的能力。部分信任应用程序有些权限是被拒绝的,因此无法直接访问那些要求此类权限的资源。其他权限是以受限方式授予的,因此可以访问需要此类权限的资源,但是要以一种受限的方式访问。例如,受限的 FileIOPermission 可能指定应用程序可访问文件系统,但只是应用程序虚拟根目录之下的目录。

为什么要使用部分信任呢?

通过将 Web 应用程序或者 Web 服务配置为部分信任,可以限制应用程序访问关键系统资源或者属于其他 Web 应用程序的资源的能力。通过仅授予应用程序需要的权限,可以构建最低特权的 Web 应用程序,在 Web 应用程序受到代码注入攻击的威胁时限制潜在的损害。

您可能遇到的问题

如果取一个现有的 Web 应用程序,重新配置其运行在部分信任级,则有可能遇到以下问题,除非应用程序在所访问的资源上受到非常严格的限制:
应用程序无法调用具有强名称的没有用 AllowPartiallyTrustedCallersAttribute (APTCA) 批注的程序集。没有 APTCA,具有强名称的程序集将发出一个完全信任要求,该要求到达部分信任 Web 应用程序时会失败。许多系统程序集只支持完全信任调用方。以下列表说明了哪些 .NET Framework 程序集支持部分信任调用方,可以被无需沙箱保护的包装程序集的部分信任 Web 应用程序直接地调用。
沙箱保护将在本单元后面详细讨论。
以下系统程序集都应用了 APTCA,这意味着它们可以被部分信任 Web 应用程序或者任何部分信任代码调用:
System.Windows.Forms.dll
System.Drawing.dll
System.dll
Mscorlib.dll
IEExecRemote.dll
Accessibility.dll
Microsoft.VisualBasic.dll
System.XML.dll
System.Web.dll
System.Web.Services.dll
System.Data.dll
如果部分信任应用程序因为调用了没有用 APTCA 标记的具有强名称的程序集而失败,将生成一个一般性的 SecurityException 异常。在此情况下,异常中不会包含更多指出调用失败的信息,因为对完全信任的要求失败。
权限要求可能一开始就失败。配置的信任级可能无法授予应用程序访问特定资源类型必要的权限。以下是一些常见的场景,可说明这一问题:
应用程序 使用事件日志或者注册表。部分信任 Web 应用程序不具备访问这些系统资源所必需的权限。如果您的代码访问这些系统资源,则将生成一个 SecurityException 异常。
应用程序使用 ADO.NET OLE DB 数据提供程序访问一个数据源。OLE DB 数据提供程序需要完全信任调用方。
应用程序调用一个 Web 服务。部分信任 Web 应用程序具有一个受限的 WebPermission,这将影响应用程序调用位于远程站点上的 Web 服务的能力。


返回页首

信任级

如果您计划将一个现有的应用程序迁移到部分信任级,一种很好的办法就是逐渐降低权限,这样就可以看到应用程序的哪些部分会出问题。例如,一开始将 trust level 属性设置为 High,然后设置为 Medium 等等。最终,所需的信任级应该取决于想要为应用程序设置的限制程度。请使用以下指导:
配置为高、中、低或者最低信任的应用程序将无法调用非托管代码或者服务组件、写事件日志、访问消息队列或者访问 OLE DB 数据源。
配置为高度信任的应用程序将有无限的对文件系统的访问权限。
配置为中度信任的应用程序有受限的文件系统访问权限。它们只能访问自己的应用程序目录层次中的文件。
配置为低度或者最低信任的应用程序无法访问 SQL Server 数据库。
最低信任的应用程序无法访问任何资源。
表 3 列出了每个 ASP.NET 信任级所授予的权限。表中省略了完全级,因为此级别将以无限状态授予所有权限。
表 3 默认的 ASP.NET 策略权限和信任级
权限和状态最低
AspNetHosting
最低
DnsPermission
无限
xx
EnvironmentPermission
无限
读取

xTEMP; TMP;
USERNAME; OS; COMPUTERNAME
EventLogPermission
FileIOPermission
无限
读取

追加
PathDiscovery
x$AppDir$
$AppDir$
$AppDir$
$AppDir$
$AppDir$

$AppDir$
IsolatedStorageFilePermission
Unrestricted
AssemblyIsolationByUser
Unrestricted UserQuota
xx
x
x
1MB
(可能随站点不同而异)
OleDbClientPermission
无限
PrintingPermission
无限
xx
ReflectionPermission
无限
ReflectionEmit
x
RegistryPermission
无限
x
SecurityPermission
Unrestricted
Assertion
Execution
ControlThread
ControlPrinicipal
RemotingConfiguration
x
x
x
x
x
x
x
x
x
x
xx
SocketPermission
无限
x
SqlClientPermission
无限
x
WebPermission
无限
x$OriginHost$


返回页首

部分信任 Web 应用程序的处理办法

如果开发一个部分信任应用程序或者启用一个现有的应用程序运行在部分信任级,将会遇到不少问题,因为应用程序将尝试访问没有授予相应权限的资源,这时候可以使用两种基本的办法:
自定义策略
自定义策略,将必需的权限授予应用程序。这有可能不可行,例如在策略限制非常严格的宿主环境中。
用沙箱保护特权代码
将资源访问代码放入一个包装程序集,授予包装程序集完全信任(而不是 Web 应用程序),并用沙箱保护特权代码的权限需求。
哪种办法正确,取决于具体问题如何。如果与这样的事实相关:需要尝试调用一个不包含 AllowPartiallyTrustedCallersAttribute 的系统程序集,那么问题就变成了如何给一段代码授予完全信任。在此情况下,您应该使用沙箱保护方式,授予用沙箱保护的包装程序集以完全信任。
自定义策略在两种方法中属于比较简单的方法,因为不需要任何开发工作。


返回页首

自定义策略

如果 Web 应用程序包含了这样的代码,它所需要的权限比某个特定 ASP.NET 信任级所授予的还要多,那么最简单的选择就是自定义一个策略文件,授予 Web 应用程序更多的代码访问安全权限。可以修改现有的策略文件并授予更多的权限,也可以根据现有的策略文件创建一个新的策略文件。
如果修改了一个内置的策略文件(例如,中度信任的 Web_mediumtrust.config 策略文件),这将影响配置为以中度信任运行的所有应用程序。
要为特定的应用程序自定义策略
1.
复制一个现有的策略文件,由此创建一个新的策略文件。例如,复制中度信任策略文件,并创建一个新的策略文件,如下所示:
%windir%/Microsoft.NET/Framework/{version}/CONFIG/web_yourtrust.config
2.
在策略文件中添加 ASP.NET 权限集必需的权限,或者修改现有的权限以授予限制性较低的权限。
3.
在 Machine.config 中的 <securityPolicy> 下为新信任级文件添加一个新的 <trustLevel> 映射,如下所示:
<securityPolicy>
<trustLevel name="Custom" policyFile="web_yourtrust.config"/>
. . .
</securityPolicy>
4.
配置应用程序以新的信任级运行,方法是配置应用程序 Web.config 文件中的 <trust> 元素,如下所示:
<system.web>
<trust level="Custom" originUrl=""/>
</system.web>


返回页首

用沙箱保护特权代码

另一种办法不需要更新 ASP.NET 代码访问安全策略,而是将您的资源访问代码包装到其自己的包装程序集中,配置机器级代码访问安全策略,以授予特定的程序集适当的权限。然后可以通过 CodeAccessPermission.Assert 方法用沙箱保护更高特权的代码,这样就无需改变 Web 应用程序被授予的整体权限了。Assert 方法防止了资源访问代码发出的安全要求传播回调用堆栈并超出包装程序集的边界。

沙箱保护模式

可以将以下模式应用于需要访问受限的资源,或者执行另一个特权操作(该特权操作的父 Web 应用程序对其没有足够权限)的任何特权代码:
1.
在包装程序集中封装资源访问代码
确保程序集具有强名称,使其可安装在 GAC 中。
2.
在访问资源之前断言相关权限
这意味着调用方必须有断言安全权限(带有 SecurityPermissionFlag.AssertionSecurityPermission)。配置为 Medium 或者更高信任级的应用程序有此权限。
断言权限是一件比较危险的事情,因为它意味着调用您代码的代码无需相应的资源访问权限,就可访问程序集封装的资源。Assert 语句表示代码可以保证其调用方的合法性。为此,您的代码应该要求另外一个权限,从而可以在调用 Assert 之前授权呼叫代码。按此方式,只允许被授予此权限的代码访问程序集公开的资源。
.NET Framework 可能无法按要求提供适合的权限。在这种情况下,可以创建和要求一个自定义权限。有关如何创建自定义权限的更多信息,请参阅本指南“如何做”部分中“如何创建自定义加密权限”单元。
3.
用 APTCA 批注包装程序集
这使部分信任 Web 应用程序可调用程序集。
4.
将包装程序集安装在 GAC 中
这将授予包装而非 Web 应用程序完全信任。ASP.NET 策略文件包含以下代码组,后者将授予 GAC 中任何程序集完全信任:
<CodeGroup
class="UnionCodeGroup"
version="1"
PermissionSetName="FullTrust">
<IMembershipCondition
class="UrlMembershipCondition"
Url="$Gac$/*"
version="1"
/>
</CodeGroup>
默认企业级和本地机器策略还要将完全信任授予位于 My Computer 区域中的任何代码,这包含安装在 GAC 中的代码。这很重要,因为所授予的权限要跨越多个策略级进行交集操作。
5.
配置 Web 应用程序信任级(例如,将其设置为“Medium”)。
图 2 说明了沙箱保护 方式。



图 2. 在特权代码自己的程序集中用沙箱保护这些代码,此程序集断言了相关权限使用单独的程序集封装资源访问,避免将资源访问代码放入 .aspx 文件或者代码隐藏文件中,是一种很好的做法。例如,创建单独的数据访问程序集封装数据库访问。这样将应用程序迁移到部分信任环境将更加简单。


返回页首

确定采用哪种办法

正确的办法取决于试图解决的问题和是否可选择修改 Web 服务器上的安全策略。

自定义策略

此方法是两种方法中相对容易的方法,而且不需要开发人员做任何工作。但是您可能不被允许修改 Web 服务器上的安全策略,而且在某些情况下,调用 .NET Framework 类库的代码可能需要完全信任。在这些情况下,就必须使用沙箱保护了。例如,以下资源要求完全信任,所以在资源访问代码访问这些资源的时候必须用沙箱进行保护:
事件日志(通过 EventLog 类)
OLE DB 数据源(通过 ADO.NET OLE DB 数据提供程序)
ODBC 数据源(通过 ADO.NET ODBC .NET 数据提供程序)
Oracle 数据库(通过 ADO.NET Oracle .NET 数据提供程序)
这个列表并不完整,但是已经包含了当前需要完全信任的常用资源类型。

沙箱保护

如果将您的特权应用程序代码放入单独的程序集,从而用沙箱保护起来,可以给程序集授予更多的权限。或者也可以授予它完全信任,而无需整个应用程序以扩展的权限运行。
例如,考虑一下使用 ADO.NET OLE DB 数据提供程序并与 System.Data.OleDb.OleDbCommand 类交互的代码。这种代码需要完全信任。虽然 System.Data.dll 程序集已经用 AllowPartiallyTrustedCallersAttribute、System.Data.OleDb.OleDbCommand 类等等进行了标记,但是它仍然无法由部分信任调用方调用,因为它是用一个完全信任的链接要求保护起来的。为了实际看一下,我们运行以下命令,从 %windir%/Microsoft.NET/Framework/{version} 目录使用 permview 实用工具:
permview /DECL /OUTPUT System.Data.Perms.txt System.Data.dll
System.Data.Perms.txt 中的输出包含以下输出结果:
class System.Data.OleDb.OleDbCommand LinktimeDemand permission set:
<PermissionSet class="System.Security.PermissionSet"
version="1" Unrestricted="true"/>
这说明保护 System.Data.OleDb.OleDbCommand 类的链接要求中使用了一个无限权限集(完全信任)。在此类情况下,配置策略来授予部分信任代码以特定的无限权限(比如 OleDbPermission)是不够的。相反,您必须用沙箱保护资源访问代码,并授予它完全信任,而最简单的实现方式是将其安装在 GAC 中。然后还要使用 Permview.exe 找出其他类的权限需求,虽然这里只显示了声明性安全属性。如果一个类必须要求完全信任,那么就无法通过 Permview.exe 查看了。这时,应该通过从部分信任代码中调用它并诊断是否有任何安全异常,来测试类的安全需求。
仅仅因为程序集用 APTCA 进行了标记,并不意味着所有包含的类都支持部分信任调用方。有些类可能包含显式的完全信任要求。


返回页首

中度信任

如果要寄宿 Web 应用程序,可以选择实现中度信任安全策略以限制特权操作。本部分集中讨论如何运行中度信任应用程序,并说明了如何克服有可能遇到的问题。
以中度信任运行有以下两个主要优点:
减少了受攻击面
应用程序独立

减少了受攻击面

因为中度信任不会授予应用程序对所有权限的无限访问权限,而是授予应用程序一个完整权限集的子集,因此您的受攻击面将减少。许多中度信任策略授予的权限还处于受限状态。即使一个攻击者因为某种原因能够控制您的应用程序,攻击者的所作所为也是受限制的。

应用程序独立

带有代码访问安全的应用程序独立限制了对系统资源和其他应用程序所拥有的资源的访问。例如,即使进程标识有可能被允许读写 Web 应用程序目录之外的文件,中度信任应用程序中的 FileIOPermission 是受限的。它只允许应用程序读取或者写自己的应用程序目录层次。


返回页首

中度信任的限制

如果您的应用程序以中度信任运行,它将面临许多限制,其中最重要的有:
无法直接地访问事件日志。
文件系统访问权限受限,只能访问应用程序虚拟目录层次中的文件。
无法直接地访问 OLE DB 数据源(虽然中度信任应用程序被授予了 SqlClientPermission 权限,允许其访问 SQL Server)。
有对 Web 服务的受限访问权限。
无法直接地访问 Windows 注册表。
本部分说明了如何从中度信任的 Web 应用程序或者 Web 服务访问以下资源类型:
OLE DB
事件日志
Web 服务
注册表

OLE DB

中度信任的 Web 应用程序没有被授予 OleDbPermission 权限。而且,OLE DB .NET 数据提供程序当前要求完全信任调用方。如果您有一个应用程序需要访问 OLE DB 数据源,同时又运行在中度信任级,应该使用沙箱保护方式。将数据访问代码放入单独的程序集,为其加上强名称,安装在 GAC 中,从而授予完全信任。
修改策略是不起作用的,除非将信任级设置为“Full”,因为 OLE DB 托管提供程序要求完全信任。
图 3 显示了这种安排。



图 3. 用沙箱保护 OLE DB 资源访问

沙箱保护

以这种方式,创建一个包装程序集封装 OLE DB 数据源访问。此程序集被授予完全信任权限,这对于使用 ADO.NET OLE DB 托管提供程序是必需的。

为了生成用沙箱保护的包装程序集,以调用 OLE DB 数据源

为数据访问代码创建一个程序集。配置程序集版本,给程序集加上强名称,并用 AllowPartiallyTrustedCallersAttribute 进行标记,如下所示:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile(@"../../oledbwrapper.snk")] [assembly:AllowPartiallyTrustedCallersAttribute()]
如果想支持部分信任调用方,必须用 AllowPartiallyTrustedCallersAttribute 批注任何具有强名称的程序集。无论何时加载和 JIT 编译具有强名称程序集的代码,都将取消 .NET Framework 做出的隐式完全信任链接要求。
请求完全信任。虽然并非绝对必要,请求完全信任仍然是一个很好的做法,因为这可使管理员通过使用 Permview.exe 一类的工具查看程序集的权限需求。要请求完全信任,应该如下所示请求无限权限集:
[assembly: PermissionSet(SecurityAction.RequestMinimum, Unrestricted=true)]
Assert 语句包装数据库调用,以断言完全信任。包装匹配的 RevertAssert 调用以消除断言的影响。虽然并非绝对必要,但是将 RevertAssert 调用放入一个 finally 块是一种很好的做法。
因为 OLE DB 提供程序要求完全信任,包装必须断言完全信任。断言一个 OleDbPermission 是不够的。步骤 7 解释了如何提高使用 CodeAccessPermission.Assert 的安全性。
public OleDbDataReader GetProductList()
{
try
{
// Assert full trust (the unrestricted permission set)
new PermissionSet(PermissionState.Unrestricted).Assert();
OleDbConnection conn = new OleDbConnection(
"Provider=SQLOLEDB; Data Source=(local);" +
"Integrated Security=SSPI; Initial Catalog=Northwind");
OleDbCommand cmd = new OleDbCommand("spRetrieveProducts", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
OleDbDataReader reader =
cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
catch(OleDbException dbex)
{
// Log and handle exception
}
catch(Exception ex)
{
//  Log and handle exception
}
finally
{
CodeAccessPermission.RevertAssert();
}
return null;
}
用以下命令生成程序集并将其安装在 GAC 中:
gacutil–i oledbwrapper.dll
为了确保程序集在每次后续的重新生成后都要添加到 GAC 中,可以在包装程序集项目中添加以下后生成事件命令行(可以在 Visual Studio.NET 中项目的属性中找到):
"C:/Program Files/Microsoft Visual Studio .NET 2003/SDK/v1.1/Bin/gacutil.exe" /i $(TargetPath)
任何 ASP.NET Web 应用程序或者 Web 服务调用的具有强名称的程序集必须安装在 GAC 中。在此例中,应该将程序集安装在 GAC 中,以确保它被授予完全信任。
配置 Web 应用程序为中度信任。添加以下代码到 Web.config 中,或者将其放入 Machine.config 中指向您的应用程序的 <location> 元素中:
<trust level="Medium" originUrl=""/>
从 ASP.NET Web 应用程序引用数据访问程序集。
因为具有强名称的程序集必须位于 GAC 而不是 Web 应用程序的 /bin 目录中,所以如果您不使用代码隐藏文件,则必须将程序集添加到应用程序使用的程序集列表中。可以使用以下命令获取程序集的 PublicKeyToken
sn–Tp oledbwrapper.dll
使用大写的 –T 开关。
然后添加以下行到 Machine.config 或者 Web.config 中:
<compilation debug="false" >
<assemblies>
<add assembly="oledbwrapper, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=4b…06"/>
</assemblies>
</compilation>
在以后连续多次重新生成包装程序集之间,您可能需要回收 ASP.NET 辅助进程,因为 ASP.NET 进程要缓存安装在 GAC 中的包装程序集。要回收 ASP.NET 辅助进程 (Aspnet_wp.exe),可以运行 IISreset.exe 实用工具。
保护调用 Assert 的代码。
Assert 调用意味着,任何调用数据访问包装的代码都可与 OLE DB 数据源交互。为了防止恶意代码调用数据访问组件,并有可能用其攻击数据库,可以在调用 Assert 之前发出一个对自定义权限的完全要求,并更新中度信任策略文件以授予 Web 应用程序自定义权限。这种解决方案需要有一定程度(虽然不是太大)的开发工作量。
有关开发自定义权限的更多信息,请参阅本指南“如何做”部分中“如何创建自定义加密权限”单元。

事件日志

EventLogPermission 类是设计用来封装访问事件日志代码的权限的。但是目前代码必须被授予完全信任,才能访问事件日志。这意味着中度信任 Web 应用程序无法直接地访问事件日志。要想访问事件日志,必须用沙箱保护事件日志记录代码。

访问事件日志

首先,确保用来运行 Web 应用程序的进程帐户(或者如果您的应用程序进行模拟,则为线程标识)能够创建事件源。为此,进程或者线程标识必须能够创建以下项下的注册表项:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Eventlog
至少任何模拟标识的 ASP.NET 进程标识必须有此注册表项的以下权限:
查询项值
设置项值
创建子项
枚举子项
通知
读取
这些设置必须应用于上述项和子项。或者,您也可以在安装时有管理性特权的情况下创建事件源。有关这种方式的更多信息,请参阅“构建安全的 ASP.NET Web 页和控件”单元中的“审核和日志记录”。

沙箱保护

为了用沙箱保护事件日志记录代码,需要创建一个包装程序集来封装事件日志访问。然后将包装程序集安装在全局程序集缓存中,这样代码访问安全策略就对其授予了完全信任。

要构建一个用沙箱保护的包装程序集来写事件日志

为事件日志代码创建一个程序集。配置程序集版本,为程序集加上强名称,并用 AllowPartiallyTrustedCallersAttribute 进行标记,如下例所示。
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile(@"../../eventlogwrapper.snk")] [assembly:AllowPartiallyTrustedCallersAttribute()]
如果想支持部分信任调用方,必须用 AllowPartiallyTrustedCallersAttribute 批注任何具有强名称的程序集。无论何时加载和 JIT 编译具有强名称程序集的代码,都将取消 .NET Framework 做出的隐式完全信任链接要求。
AllowPartiallyTrustedCallersAttribute 是在 System.Security 命名空间中定义的,因此必须用一条 using 语句引用这个命名空间。
请求适当的权限。
虽然并非绝对必要,请求适当的权限仍然是一个很好的做法,因为这允许一个管理员使用 Permview.exe 之类的工具查看程序集的权限需求。因为事件日志程序集可以从部分信任调用方访问,这个程序集就不需要请求完全信任权限集了。在此例中程序集只是写特定机器上的事件日志,因此,只需要以下权限请求:
[assembly:EventLogPermissionAttribute(SecurityAction.RequestMinimum,
MachineName="",
PermissionAccess=EventLogPermissionAccess.Instrument)]
但是如果您的程序集需要请求完全信任,应该如下所示请求无限的权限集:
[assembly: PermissionSet(SecurityAction.RequestMinimum, Unrestricted=true)]
用断言完全信任的 Assert 语句和匹配的起断言相反作用的 RevertAssert 语句包装事件日志调用。虽然并非绝对必要,但是在 finally 块中调用 RevertAssert 是一个很好的做法。以下代码将一个 Information 项写入 Application 日志,文本为“Writing to event log”:
try
{
string source = "Event Source";
string log = "Application";
string eventText = "Writing to the event log";
EventLogEntryType eventType = EventLogEntryType.Information;

//Assert permission
EventLogPermission eventPerm;
eventPerm = new EventLogPermission(EventLogPermissionAccess.Instrument,
"");
eventPerm.Assert();

//Check to see if the source exists.
if(!EventLog.SourceExists(source))
{//The keys do not exist, so register your application as a source
EventLog.CreateEventSource(source, log);
}

//Write to the log.
EventLog.WriteEntry(source, eventText, eventType);
}
catch(Exception ex)
{/*Handle exception*/}
finally
{
CodeAccessPermission.RevertAssert();
}
使用以下命令生成程序集并将其安装在 GAC 中:
gacutil–i eventlogwrapper.dll
为了确保程序集在每次后续的重新生成后都要添加到 GAC 中,可以在包装程序集项目中添加以下后生成事件命令行(可以在 Visual Studio.NET 中项目的属性中找到):
"C:/Program Files/Microsoft Visual Studio .NET 2003/SDK/v1.1/Bin/gacutil.exe" /i $(TargetPath)
任何 ASP.NET Web 应用程序或者 Web 服务调用的具有强名称的程序集必须安装在 GAC 中。安装在 GAC 中的程序集默认时代码访问安全策略都会授予完全信任。
配置 Web 应用程序为中度信任。在 Web.config 中添加以下内容,或者将其放入 Machine.config 中指向应用程序的 <location> 元素中:
<trust level="Medium" originUrl=""/>
从 ASP.NET Web 应用程序引用事件日志程序集。
因为具有强名称的程序集必须在 GAC 中,而不在 Web 应用程序的 /bin 目录中,所以如果没有使用代码隐藏文件,就必须将程序集添加到应用程序所使用的程序集列表中。可以使用以下命令获取程序集的 PublicKeyToken
sn–Tp eventlogwapper.dll
使用大写的 –T 开关。
然后添加以下代码到 Machine.config 或者 Web.config 中:
<compilation debug="false" >
<assemblies>
<add assembly="eventlogwrapper, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=4b…06"/>
</assemblies>
</compilation>
在以后连续多次重新生成包装程序集之间,您可能需要回收 ASP.NET 辅助进程,因为 ASP.NET 进程要缓存安装在 GAC 中的包装程序集。要回收 ASP.NET 辅助进程 (Aspnet_wp.exe),可以运行 iisreset.exe 实用工具。
保护调用 Assert 方法的代码。Assert 调用意味着任何调用事件日志包装的代码能够与事件日志交互。为了防止恶意代码调用事件日志包装,并可能使用它填写事件日志,可以在调用 Assert 之前发出一个对自定义权限的完全要求,并更新中度信任策略文件以授予 Web 应用程序自定义权限。这种解决方案需要有一定程度(虽然不是太大)的开发工作量。
有关如何开发自定义权限的更多信息,请参阅本指南“如何做”部分中“如何创建自定义加密权限”单元。

Web 服务

默认时,中度信任策略将授予 ASP.NET Web 应用程序受限的 WebPermission 权限。为了能够从您的 Web 应用程序调用 Web 服务,必须配置应用程序的 <trust> 元素的 originUrl 属性。

要从中度信任 Web 应用程序调用一个 Web 服务

1.
配置应用程序运行在中度信任级。
2.
originUrl 设置为指向您希望能够调用的 Web 服务,如下所示:
<trust level="Medium" originUrl="http://servername/.*"/>
originUrl 值用于 System.Text.RegEx 正则表达式类的构造函数中,可以执行对 Web 服务可访问的 URL 的匹配。这个 RegEx 类是与 WebPermission 类结合使用的。“.*”匹配任何以“http:// servername/”开始的 URL。
originUrl 属性在计算 ASP.NET 策略时使用。它给 $OriginHost$ 替换参数提供值。以下是来自 Web_mediumtrust.config 的 WebPermission 定义:
<IPermission
class="WebPermission"
version="1">
<ConnectAccess>
<URI uri="$OriginHost$"/>
</ConnectAccess>
</IPermission>
如果不指定应用程序要访问的 Web 服务器,任何 Web 服务请求都将失败,同时产生一个 SecurityException 异常。为了调用本地 Web 服务器上的 Web 服务,应使用以下配置:
<trust level="Medium" originUrl="http://localhost/.*" />
如果您的应用程序需要访问不同服务器上的多个 Web 服务,需要自定义 ASP.NET 策略,因为在 Web.config 或者 Machine.config 中的 <trust> 元素上只可以指定一个 originUrl

要从中度信任的应用程序调用多个 Web 服务

1.
将 Web_mediumtrust.config 文件(位于以下目录中)复制到一个名为 Web_mediumtrust_WebService.config 的文件中,该文件也位于同一目录。
%windir%/Microsoft.NET/Framework/{version}/CONFIG
2.
找到 WebPermission,并为每个要访问的服务器添加一个 <URI> 元素,如下所示:
<IPermission class="WebPermission" version="1">
<ConnectAccess>
<URI uri="$OriginHost$"/>
<URI uri="http://server1/.*"/>
<URI uri="http://server2/.*"/>
<URI uri="http://server3/.*"/>
</ConnectAccess>
</IPermission>
如果您使用 NetBIOS 名称、DNS 名称和/或 IP 地址调用 Web 服务,每个 URI 必须有一个单独的 <URI> 元素,如下例所示。
<IPermission class="WebPermission" version="1">
<ConnectAccess>
<URI uri="$OriginHost$"/>
<URI uri="http://servername.yourDomain.com/.*"/>
<URI uri="http:// servername/.*"/>
<URI uri="http://127.0.0.1/.*"/>
</ConnectAccess>
</IPermission>
3.
保存文件。
4.
将应用程序的 Web.config 文件更新,指向新创建的策略文件。这需要您创建一个新的信任级,并将其映射到新的策略文件。接下来,配置应用程序的 <trust> 元素以使用新的级别。
以下代码片段说明了 Web.config 中必要的添加:
<system.web>
<securityPolicy>
<trustLevel name="MediumPlusWebPermission"
policyFile="web_mediumtrust_WebService.config"/>
</securityPolicy>
<trust level=" MediumPlusWebPermission" originUrl=""/>
</system.web>

使用默认凭据

您可能需要调用一个使用 Windows 身份验证的 Web 服务,并通过代理凭据缓存指定身份验证凭据。例如:
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
在这种情况下,ASP.NET 应用程序需要有对 USERNAME 环境变量读取访问权限的 EnvironmentPermission。默认中度信任策略可授予 Web 应用程序该权限。
在 ASP.NET 服务器端情况下,凭据是从 ASP.NET 应用程序的线程级或者进程级标记获取的。如果 DefaultCredentials 是从一个桌面应用程序使用的,将使用当前交互用户的标记。要求 EnvironmentPermission 是一种降低风险的策略,目的是确保代码无法随意使用本地用户的凭据,并向网络公开。

注册表

默认时,中度信任的 Web 应用程序不被授予 RegistryPermission。为了配置应用程序以访问注册表,必须要么修改 ASP.NET 策略以授予应用程序此权限,要么开发一个用沙箱保护的具有必要权限的包装程序集。
沙箱保护方式与前面叙述的 OLE DB 数据源和事件日志中的相同。

自定义策略

自定义策略最简单的方式,是根据中度信任策略文件创建一个自定义策略文件,并配置应用程序以使用自定义策略。自定义策略将授予应用程序 RegistryPermission 权限。

要创建一个自定义策略以允许注册表访问

将 Web_mediumtrust.config 文件(位于以下目录中)复制到一个名为 Web_mediumtrust_Registry.config 的文件中,该文件也位于同一目录。
%windir%/Microsoft.NET/Framework/{version}/CONFIG
通过复制然后创建自定义的策略文件,可以避免直接修改 Web_mediumtrust.config 文件。直接修改默认中度信任文件,会影响所有机器上配置为中度信任的应用程序。
找到 <SecurityClasses> 元素,并添加如下内容,以注册 RegistryPermission 类:
<SecurityClass Name="RegistryPermission"
Description="System.Security.Permissions.RegistryPermission,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
找到 ASP.NET 权限集,并在权限集中添加无限的 RegistryPermission,如下所示:
<IPermission class="RegistryPermission" version="1" Unrestricted="true"
保存文件。
更新 Machine.config 以创建一个新的对应于新策略文件的信任级。
<system.web>
<securityPolicy>
<trustLevel name="MediumPlusRegistry"
policyFile="web_mediumtrust_Registry.config "/>
</securityPolicy>
更新应用程序的 Web.config,配置应用程序的 <trust> 级。
<system.web>
<trust level="MediumPlusRegistry" originUrl=""/>
</system.web>


返回页首

小结

代码访问安全是一种可以用来帮助提供应用程序独立的资源约束安全模型。应用程序可以配置为运行在各种部分信任级。信任级确定了授予 ASP.NET Web 应用程序或者 Web 服务的权限。这继而确定了可以访问的资源类型和其他可以执行的特权操作类型。请注意所有资源访问最终都要受操作系统安全的限制。
推荐的独立模型是在 Windows Server 2003 上使用 IIS 6.0 应用程序池,并在代码访问安全之外提供进程级独立。在 Windows 2000 上,独立只能使用代码访问安全和单独的线程标识获得。
将一个应用程序迁移为以部分信任运行,通常需要一定量的重新设计。如果应用程序要访问部分信任级不允许的资源,或者如果它要调用不包含 APTCA 的具有强名称的程序集,就可能需要进行重新设计。在这些情况下,可以在单独的包装程序集中用沙箱保护特权资源访问。在某些情况下,可能能够创建并使用自定义策略文件,虽然这取决于 Web 服务器的安全策略。
将资源访问代码放入单独的程序集,并避免将此代码存入 .aspx 文件和代码隐藏文件中,是一种很好的设计实践。使用单独的程序集可以使代码访问安全策略独立地应用于来自 Web 应用程序的程序集,这使您可开发用沙箱保护的可信代码来执行资源访问。


返回页首

其他资源

有关更多信息,请参阅下列资源:
MSDN Magazine 中的“.NET 中的安全:CLR 的安全基础结构提供证据、策略、权限和强制服务”,网址在:http://msdn.microsoft.com/msdnmag/issues/02/09/SecurityinNET/default.aspx
MSDN Magazine 中的“.NET 中的安全:用公共语言运行库强制代码访问权限”,网址在:http://msdn.microsoft.com/msdnmag/issues/01/02/CAS/default.aspx
LaMacchia、Lange、Lyons、Martin 和 Price 的 .NET Framework Security.Addison Wesley Professional,2002。
本指南“如何……”部分中的“如何创建自定义加密权限”。
转到原英文页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息