本页内容
本模块内容
目标
适用范围
如何使用本模块
概述
资源访问
完全信任和部分信任
在 ASP.NET 中配置代码访问安全性
ASP.NET 策略文件
ASP.NET 策略
开发部分信任 Web 应用程序
信任级别
部分信任 Web 应用程序的方法
自定义策略
sandbox 特权代码
决定采用的方法
中级信任
中级信任限制
小结
其他资源
本模块内容
代码访问安全性是一种资源限制模型,它允许管理员决定指定的代码是否可访问特定资源,以及如何访问特定资源。它同时允许管理员执行其他特权操作。本模块重点介绍了如何配置 ASP.NET 代码访问安全性策略,以及如何处理在部分信任 Web 应用程序开发阶段中遇到的主要问题。
模块详细说明了代码访问安全性的实际元素,您将了解如何开发得益于代码访问安全性保护的中级信任 Web 应用程序,尽管这些应用程序仍要使用完全信任组件。
此外,本模块还包括了创建自定义 ASP.NET 信任策略的相关内容,以及两个非常重要的列表:
• 应用 APTCA (AllowPartiallyTrustedCallersAttribute) 的系统程序集。
• 默认 ASP.NET 策略权限和信任级别。它具体说明了每个 ASP.NET 信任级别的主要限制。
返回页首
目标
使用本模块可以实现:
• 了解 ASP.NET 策略文件如何工作,如何创建自定义策略。
• 开发部分信任 Web 应用程序。
• 使用部分信任 Web 应用程序中的 OLE DB、事件日志、Web 服务和注册表。
• Sandbox 特权代码。
• 了解何时使用 sandbox 方法、何时自定义现有 ASP.NET 信任策略。
返回页首
适用范围
本模块适用于下列产品和技术:
• Microsoft® Windows® 2000 Server and Microsoft Windows Server™ 2003
• Microsoft .NET Framework 1.1 和 ASP.NET 1.1
返回页首
如何使用本模块
本模块不涉及代码访问安全性的基础。尽管重要概念将在适当的时候反复讲到,但您仍需了解一定的必备知识。有关代码访问安全性工作原理的详细信息,请参阅模块 8 代码访问安全的实践。
使用本模块可了解如何使用代码访问安全性来锁定 Web 应用程序,同时使服务得以强化以免受攻击。
如果要管理共享的宿主环境,或本身是运行多家公司应用程序的 Internet 服务提供商 (ISP),并且都在同一 Web 服务器中运行,则通过使用代码访问安全性您可以:
• 使应用程序相互隔离。
例如,使用代码访问安全性确保 Web 应用程序不能写入另一 Web 应用程序目录。
• 使应用程序与系统资源隔离。
例如,代码访问安全性可限制对文件系统、注册表、事件日志、网络资源及其他系统资源的访问。
请注意,Windows Server 2003 和 Internet 信息服务 (IIS) 6.0 为 Web 应用程序提供了进一步的进程隔离。建议使用的应用程序隔离模型是,进程隔离加代码访问安全性。
有关详细信息,请参阅模块 20 托管多个 Web 应用程序。
返回页首
概述
传统的基于主体的安全性(如由操作系统提供的)可基于用户身份授予资源的访问权限。
如果使用 Microsoft .NET Framework 版本 1.1,管理员可为 ASP.NET Web 应用程序和 Web 服务配置策略,这些应用程序和服务可由多个程序集组成。您也可授予它们一定的代码访问安全性权限,允许应用程序访问特定的资源类型并执行特定的特权操作。
例如:
• 管理员可决定,下载自网络的代码不应被授予访问任何资源的权限;而由特定公司开发的 Web 应用程序代码必须有较高的信任度(如允许访问文件系统、事件日志和 Microsoft SQL Server 数据库等)。
• 本地管理员启动的程序在本地计算机中没有限制。不幸的是,如果恶意用户骗取了管理员身份,也就能使用管理员安全上下文来执行代码,且没有限制。
这些区域的代码访问安全性很重要,因为它基于代码本身(而非运行代码的用户)提供附加的限制和安全性。
注意:使用 .NET Framework 版本 1.0 构建的 Web 应用程序和 Web 服务在运行时始终有无限制的代码访问权限。这是不可配置的。
返回页首
资源访问
源自 ASP.NET 应用程序和托管代码的所有资源访问大致属于下面两种安全层:
• 代码访问安全性。此安全层可验证当前调用堆栈中的所有代码(无论是准备生成资源访问代码,还是包括资源访问代码)是否被授予资源的访问权限。管理员可使用代码访问安全性策略将权限授予程序集。权限可准确界定哪些程序集类型能访问。对应于不同资源类型的便是各种权限类型。这些类型有:文件系统、注册表、事件日志、目录服务、Microsoft SQL Server™、OLE DB 数据源和网络资源。
有关代码访问权限的完整列表,请参阅模块 8 代码访问安全的实践。
• 操作系统/平台安全。此安全层可验证请求线程的安全上下文是否能访问资源。如果正在模拟线程,则使用线程模拟令牌。否则,系统会将进程令牌并与资源附加的访问控制列表 (ACL) 相比较,然后决定是否执行请求的操作并访问资源。
要成功访问资源,上两项检查都必须成功。 .NET Framework 类的所有资源类型都由代码访问权限保护。图 9.1 显示了 Web 应用程序访问的公用资源类型范围,以及成功访问所必需的关联代码访问权限。
图 9.1
ASP.NET Web 应用程序访问的公用资源类型和关联访问权限
返回页首
完全信任和部分信任
在默认情况下,Web 应用程序在运行时有完全信任权限。完全信任应用程序的无限制代码访问权限由代码访问安全性策略授予。这些权限包括内置系统和自定义权限。这意味着,代码访问安全性不会阻止应用程序访问如图 9.1 所示的任意安全资源类型。资源访问成功与否完全取决于操作系统级安全性。运行时完全信任的 Web 应用程序包括了使用 .NET Framework 版本 1.0 生成的所有 ASP.NET 应用程序。在默认情况下,.NET Framework 版本 1.1 应用程序的运行是完全信任的,但信任级别可通过
元素(本模块稍后介绍)配置。
如果应用程序的信任级别不是“完全”,此程序是部分信任应用程序。部分信任应用程序的权限有限,只能访问安全资源。
要点:构建于 .NET Framework 1.0 版本之上的 Web 应用程序始终按完全信任级别运行,因为 System.Web 中的类型要求调用者被完全信任。
返回页首
在 ASP.NET 中配置代码访问安全性
在默认情况下,Web 应用程序按完全信任级别运行,且权限无限制。要修改 ASP.NET 中代码访问安全性的信任级别,必须在 Machine.config 或 Web.config 中设置一项参数,然后将应用程序配置为部分信任应用程序。
配置信任级别
Machine.config 中的 元素控制了是否启用 Web 应用程序的代码访问安全性。打开 Machine.config,搜索 ,您可看到下列内容。
如果将信任级别设置为“完全”,代码访问安全性停用,因为权限要求资源的访问不受阻碍。这是构建于 .NET Framework 1.0 版本之上的 Web 应用程序的唯一选项。参考下面从“完全”到“最低”的权限列表,每个级别都去掉了若干权限。通过逐步限制应用程序的权限,使之只能访问安全的资源并执行特权操作。每个级别都产生更大程度的应用程序隔离。表 9.1 显示了预定义信任级别,指出了与上一级别相比的主要限制。
表 9.1 ASP.NET 信任级别的限制
ASP.NET 信任级别 主要限制
完全
无限制的权限。应用程序可访问任何属于操作系统安全范围的资源。支持所有的特权操作。
高
不能调用未托管代码
不能调用服务组件
不能写入事件日志
不能访问 Microsoft 消息队列
不能访问 OLE DB 数据源
中
除上述限制外,还限制访问当前应用程序目录中的文件,不允许访问注册表。
低
除上述限制外,应用程序不能与 SQL Server 连接,代码不能调用 CodeAccessPermission.Assert(无断言安全权限)。
最低
仅有执行权限。
锁定信任级别
如果 Web 服务器管理员希望通过代码访问安全性来确保应用程序隔离,并限制对系统资源的访问,管理员必须能在计算机级别上定义安全策略并阻止个人程序替代它。
应用程序服务提供商(或任何负责运行同一服务器各种 Web 应用程序的人)都必须锁定所有 Web 应用程序的信任级别。为此,请在 Machine.config 文件的 标记中增加 元素,将 allowOverride 属性设置为 false,如下例所示。
您也可以在 元素中使用 path 属性,以便使配置应用到特定的站点或不能被替代的 Web 应用程序。有关 元素的详细信息,请参阅模块 19 确保 ASP.NET 应用程序和 Web Services 的安全。
返回页首
ASP.NET 策略文件
每个信任级别都映射到个人的 XML 策略文件,策略文件则列举了每个信任级别授予的权限集。策略文件位于如下目录:
%windir%\Microsoft.NET\Framework\{version}\CONFIG
信任级别由 Machine.config 文件中的 元素(位于 元素上方)映射至策略文件,如下例所示。
注意:不存在完全信任级别的策略文件。这是一种特殊情况,仅指出了所有无限制权限集。
ASP.NET 策略完全可重新配置。除了默认策略级别外,管理员可创建自定义的权限文件,然后使用本模块随后描述的 元素进行配置。与自定义级别相关联的策略文件也必须由 Machine.config 中的 定义。
返回页首
ASP.NET 策略
代码访问安全性策略有一定的层次结构,并在多个级别上管理。您可以为企业、计算机、用户和应用程序域级别创建策略。ASP.NET 代码访问安全性策略是一种应用程序域级别策略实例。
不同 XML 配置文件中的设置定义了每个级别的策略。企业、计算机和用户策略可通过 Microsoft .NET Framework 配置工具来配置,但 ASP.NET 策略文件必须使用 XML 或文本编辑器手动编辑。
单个 ASP.NET 信任级别策略文件说明了在特定信任级别配置的应用程序可能被授予哪些权限。“实际”授予 ASP.NET 应用程序的权限都要交叉“所有”策略级别中授予的权限来决定,“所有”策略级别包括企业、计算机、用户和 ASP.NET(应用程序域)级别策略。
由于策略是沿企业级至 ASP.NET 应用程序级评估的,所以权限只能依次减少。如果一开始没有授予较高的权限,将不能在 ASP.NET 级别添加权限。此方法可确保企业管理员始终有最终发言权,在应用程序域中运行的恶意代码不能请求并得到比管理员更多的权限。
有关策略评估的详细信息,请参阅模块 8 代码访问安全的实践。
ASP.NET 策略文件内容
要查看由特定级别定义的权限,请通过“记事本”或 XML 编辑器(首选)打开相关策略文件,然后找到名为“ASP.NET”的权限集。此权限集列举了在当前信任级别为应用程序配置的权限。
注意:您也将看到“FullTrust”和“Nothing”权限集。这些权限集不包含权限元素,因为“FullTrus”暗含了所有权限,“Nothing”暗含没有权限。
下面是 ASP.NET 策略文件的主要元素:
... 安全类、权限类型、
代码组类型等的列表...
... 这是相关部分...
... 各权限的列表...
class="AspNetHostingPermission"
version="1"
Level="High" />
class="DnsPermission"
version="1"
Unrestricted="true" />
...权限列表(续)...
注意:每个权限都由 元素定义,它定义了权限类型名称、版本和是否处于无限制状态。
权限状态和无限制权限
很多权限包括状态,用于微调由权限指定的访问权限。状态准确界定了权限允许应用程序所做的事情,如 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.Web”和“System.Web.Mobile”中的所有公用类型都受此权限“最低”级别请求的保护。设计风险缓解策略的目的是,确保 Web 应用程序代码在未得到管理员的策略配置前,不能用于其他部分信任环境。
替代参数
在编辑某一 ASP.NET 策略文件时,您会注意到一些权限元素包含替代参数($AppDirUrl$、 $CodeGen$、$Gac$)。替代参数允许您配置程序集的权限,这些程序集是 Web 应用程序的一部分,但从不同位置加载。每个替代参数将在系统评估安全策略时由实际值替代(发生于首次加载 Web 应用程序程序集时)。Web 应用程序可能有如下三种程序集类型:
• 专用程序集,在构建时编译并保存在应用程序 bin 目录中。
要点:此类型的程序集不能是强名称。ASP.NET Web 应用程序使用的强名称程序集必须安装在全局程序集缓存中。鉴于多应用程序域工作进程的内部机理,这种限制是必要的。
• 动态编译的程序集,响应页面请求时生成。
• 共享程序集,从计算机的全局程序集缓存中加载。
每个程序集类型都有相关联的替代参数,见表 9.2 中的汇总。
表 9.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 应用程序并使之按部分信任级别运行,除非应用程序严格限制在要访问的资源范围中,否则您很可能遇到下面的问题:
• 应用程序无法调用不采用“AllowPartiallyTrustedCallersAttribute”(APTCA) 批注的强名称程序集。没有 APTCA,强名称程序集将发出完全信任请求,在请求到达部分信任 Web 应用程序时,该请求失败。很多系统程序集仅支持完全信任调用者。下表显示了哪些 .NET Framework 程序集支持部分信任调用者,并能由部分信任的 Web 应用程序直接调用(无需必备 sandbox 的包装程序集)。
注意:sandbox 将在本模块后面详细讨论。
下面的系统程序集应用了 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 服务的能力。
返回页首
信任级别
如果计划让现有应用程序迁移到部分信任级别,最好的方法是逐步减少权限,以便看到应用程序的中断部分。例如,一开始将信任的 level 属性设置为“高”,然后设置为“中”,依此类推。最后,具体的目标信任级别取决于您对应用程序施加的限制程度。请参考下面的指导:
• 高、中、低或最低信任级别的应用程序不能调用未托管代码或服务组件,不能写入事件日志、访问消息队列或访问 OLE DB 数据源。
• 高信任级别的应用程序对文件系统的访问权限不受限制。
• 中信任级别的应用程序对文件系统的访问权限有一定限制。它们只能访问自己所在应用程序目录层中的文件。
• 低或最低信任级别的应用程序不能访问 SQL Server 数据库。
• 最低信任级别的应用程序不能访问任何资源。
表 9.3 显示了每个 ASP.NET 信任级别授予的权限。表中省略了完全信任级别,它授予的所有权限都不受限制。
表 9.3 默认 ASP.NET 策略权限和信任级别
权限和状态 高 中 低 最低
AspNetHosting
级别
高
中
低
最低
DnsPermission
无限制的
EnvironmentPermission
无限制的
读、写
TEMP; TMP;
USERNAME;
OS;
COMPUTER
NAME
EventLogPermission
FileIOPermission
无限制的
读
写
附加
PathDiscovery
$AppDir$
$AppDir$
$AppDir$
$AppDir$
$AppDir$
$AppDir$
IsolatedStorageFilePermission
无限制的
AssemblyIsolationByUser
无限制的 UserQuota
1 MB
(随站点的不同而变化)
OleDbClientPermission
无限制的
PrintingPermission
无限制的
DefaultPrinting
ReflectionPermission
无限制的
ReflectionEmit
RegistryPermission
无限制的
SecurityPermission
无限制的
断言
执行
ControlThread ControlPrinicipal
RemotingConfiguration
SocketPermission
无限制的
SqlClientPermission
无限制的
WebPermission
无限制的
$OriginHost$
返回页首
部分信任 Web 应用程序的方法
如果要开发部分信任应用程序,或按部分信任级别运行当前应用程序,您将遇到一些问题。原因是应用程序未被授予相关的权限来访问资源,您可使用两种基本方法:
• 自定义策略
自定义策略来授予应用程序必需的权限。这可能并不可行,例如在宿主环境中,策略限制非常严格。
• sandbox 特权代码
请将资源访问代码置于包装程序集,然后授予包装程序集完全信任(非 Web 应用程序),再使用 sandbox 处理特权代码的权限请求。
具体采用怎样的正确方法取决于问题本质。如果您试图调用不包含“AllowPartiallyTrustedCallersAttribute”的系统程序集,问题就变为如何赋予一段代码以完全信任。在本方案中,您必须使用 sandbox 方法,并授予使用 sandbox 方法的包装程序集以完全信任。
注意:自定义策略是两种方法中较容易的一种,它不需要任何开发。
返回页首
自定义策略
如果 Web 应用程序所含代码要求的权限比特定 ASP.NET 信任级别授予的权限还要多,最简单的选择是自定义策略文件,然后以此授予 Web 应用程序附加的代码访问安全性权限。您可以修改当前的策略文件,然后授予其他权限或基于当前策略文件创建新策略。
注意:如果修改某一内置策略文件(例如,中级信任的 Web_mediumtrust.config 策略文件),将影响所有按中信任级别运行的应用程序。
• 为特定应用程序自定义策略
1.
复制现有策略文件之一,创建新策略文件。例如,复制中级信任策略文件,然后创建新的策略文件,具体如下:
%windir%\Microsoft.NET\Framework\{version}\CONFIG\web_yourtrust.config
2.
将必要的权限添加到策略文件的 ASP.NET 权限集,或采用另一方法,即修改当前权限,然后授予限制性较少的权限。
3.
为新信任级别文件添加新的 ,映射到 Machine.config 文件中的 ,如下所示:
. . .
4.
配置应用程序 Web.config 文件中的 元素,使应用程序按新的信任级别运行。如下所示:
返回页首
sandbox 特权代码
另一种无需更新 ASP.NET 代码访问安全性策略的方法是,将资源访问代码包装在自已的包装程序集中,配置计算机级代码访问安全性策略,并授予特定程序集以适当的权限。然后,运行“CodeAccessPermission.Assert”方法使 sandbox 方法处理有更高特权的代码,您因此不必更改 Web 应用程序的全部权限。Assert 方法可防止由资源访问代码发出的安全请求将备份调用堆栈传播到包装程序集范围以外。
sandbox 模式
您可以将下面的模式应用到任意特权代码,这些特权代码要访问受限制的资源或执行其他特权操作,它们在父级 Web 应用程序中因权限不足而无法实现:
1.
将资源访问代码封装在包装程序集中。
确保程序集是强名称,以便安装在 GAC 中。
2.
在访问资源前断言相关权限。
这意味着,调用者必须具有断言安全权限(使用“SecurityPermissionFlag.Assertion”方法的“SecurityPermission”)配置为中或高信任级别的应用程序有此权限。
断言权限非常危险,它意味着调用您代码的代码可访问程序集所封装的资源,且不需要相关的资源访问权限。Assert 语句假定您的代码能够确保调用者的合法性。为此,您的代码必须请求备用的权限,以便在调用 Assert 前向调用代码授权。如果使用这种方法,仅允许已授予备用权限的代码来访问程序集公开的资源。
.NET Framework 可能不会向请求提供适当的权限。在这种情况下,您可以创建并请求自定义权限。有关创建自定义权限的详细信息,请参阅本指南的如何:创建自定义加密权限一节。
3.
使用 APTCA 批注包装程序集。
允许部分信任 Web 应用程序调用程序集。
4.
在 GAC 中安装包装程序集。
赋予包装以完全信任,但不赋予 Web 应用程序。ASP.NET 策略文件包含下列代码组,它们向位于 GAC 中的任意程序集授予完全信任:
class="UnionCodeGroup"
version="1"
PermissionSetName="FullTrust>
class="UrlMembershipCondition"
Url="$Gac$/*"
version="1"
/>
注意:默认的企业和本地机策略也向“我的电脑”中的所有代码授予了完全信任,包括安装在 GAC 中的代码。这一点很重要,因为已授予的权限在整个策略级别上相互交叉。
5.
配置 Web 应用程序信任级别(例如,设置为“中”)。
图 9.2 显示了 sandbox 方法。
图 9.2
本身程序集中的 sandbox 特权代码,断言了相关权限
最佳做法是,使用单独的程序集封装资源访问,避免将资源访问代码置于 .aspx 文件或代码隐藏文件中。例如,创建单独的数据访问程序集来封装数据库访问。这可使应用程序到部分信任环境的迁移变得更加容易。
返回页首
决定采用的方法
具体使用怎样的方法取决于问题的本质,以及是否在 Web 服务器中修改安全策略选项。
自定义策略
此方法是这两种方法中较容易的一种,不需要任何开发工作。但是,系统可能不允许您修改 Web 服务器中的策略。在有些方案中,调用 .NET Framework 类库的代码可能需要完全信任。在这些情况下,必须使用 sandbox。例如,下面的资源需要完全信任。您必须在访问资源访问代码时使用 sandbox 方法。
• 事件日志(通过 EventLog 类)
• OLE DB 数据源(通过 ADO.NET OLE DB 数据提供程序)
• ODBC 数据源(通过 ADO.NET ODBC .NET 数据提供程序)
• Oracle 数据库(通过 ADO.NET Oracle .NET 数据提供程序)
注意:此列表没有详尽说明所有资源类型,但它包括常用的、需要完全信任的资源类型。
使用 sandbox 方法
如果在单独的程序集中使用 sandbox,可向程序集授予附加权限。另一种授予完全信任的方法是,您无需运行整个应用程序来使用扩展的权限。
例如,考虑那些使用 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:
version="1" Unrestricted="true"/>
这说明无限制权限集(完全信任)用在保护“System.Data.OleDb.OleDbCommand”类的链接请求中。在类似方案中,将策略配置为向部分信任代码授予指定的无限制权限(如“OleDbPermission”)还不够。您必须使用 sandbox 方法处理资源访问代码,然后授予它完全信任。最简单的方法就是将代码安装在 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 数据源,请使用 sandbox 方法。将数据访问代码置于单独的程序集,赋予它强名称,然后将它安装在能授予完全信任权限的 GAC 中。
注意:除非将信任级别设置为“完全”,否则修改策略不起作用,因为 OLE DB 托管提供程序要求完全信任。
图 9.3 显示了相关安排。
图 9.3
使用 sandbox 方法处理 OLE DB 资源访问
使用 sandbox 方法
在本方法中,您将创建包装程序集来封装 OLE DB 数据源访问。此程序集被授予完全信任权限,这是使用 ADO.NET OLE DB 托管提供程序所必需的。
• 构建使用 sandbox 方法的包装程序集来调用 OLE DB 数据源
1.
为数据访问代码构建程序集。配置程序集版本,赋予程序集以强名称,使用“AllowPartiallyTrustedCallersAttribute”标记,如下所示:
[assembly:AssemblyVersion("1.0.0.0")]
[assembly:AssemblyKeyFile(@"..\..\oledbwrapper.snk")]
[assembly:AllowPartiallyTrustedCallersAttribute()]
如果希望支持部分信任调用者,您必须使用“AllowPartiallyTrustedCallersAttribute”批注所有强名称程序集。只要强名称程序集中的代码被加载且 JIT 编译,都将抑制 .NET Framework 的隐式完全信任链接请求。
2.
请求完全信任。从严格意义上讲,请求完全信任并非必要,但它却是比较好的做法。因为它允许管理员使用类似 Permview.exe 的工具来查看程序集的权限要求。要请求完全信任和无限制权限,方法如下:
[assembly:PermissionSet(SecurityAction.RequestMinimum, Unrestricted=true)]
3.
使用“Assert”语句包装数据库调用,从而断言完全信任。包装匹配的“RevertAssert”调用可逆转断言结果。从严格意义上讲,使调用置于“finally”块的“RevertAssert”并非必要,但却是比较好的做法。
因为 OLE DB 提供程序要求完全信任,包装必须断言完全信任。断言“OleDbPermission”是不够的。步骤 7 说明了如何提高使用“CodeAccessPermission.Assert”的安全性。
public OleDbDataReader GetProductList()
{
try
{
//断言完全信任(无限制权限集)
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)
{
//记录日志、处理异常
}
catch(Exception ex)
{
//记录日志、处理异常
}
finally
{
CodeAccessPermission.RevertAssert();
}
return null;
}
4.
使用下面的命令构建程序集,然后将它安装在 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 中,以保证授予完全信任。
5.
配置 Web 应用程序中级信任。将下面的代码添加到 Web.config 文件中,置于指向应用程序的 元素中。
6.
引用 ASP.NET Web 应用程序中的数据访问程序集。
由于强名称程序集一定在 GAC 中(不在 Web 应用程序的 \bin 目录中),如果您不在文件后使用代码,一定要将程序集添加到应用程序使用的程序集列表中。您可以使用下面的命令获得程序集的“PublicKeyToken”:
sn -Tp oledbwrapper.dll
注意:使用大写的 –T 参数。
然后,将下面的内容添加到 Machine.config 或 Web.config 文件:
注意:在包装程序集的连续重建过程中,您可能需要循环 ASP.NET 工作进程,因为安装在 GAC 中的包装程序集由 ASP.NET 进程缓存。通过循环 ASP.NET 工作进程 (Aspnet_wp.exe),您可运行 IISreset.exe 实用程序。
7.
保护调用“Assert”的代码。
“Assert”调用意味着所有调用数据访问包装的代码都能与 OLE DB 数据源交互。要防止恶意代码调用数据访问组件并使用该组件攻击数据库,您可在调用“Asserrt”并更新中级信任策略文件以授予 Web 应用程序自定义权限之前,发出自定义权限的完全权限请求。本解决方案需要一定量的开发工作。
有关开发自定义权限的详细信息,请参阅本指南的如何:创建自定义加密权限一节。
事件日志
设计“EventLogPermission”类的目的是封装代码权限,从而访问事件日志。但目前,必须授予代码完全信任权限以访问事件日志。这意味着,中级信任 Web 应用程序不能直接访问事件日志。为此,您必须使用 sandbox 方法处理事件日志记录代码。
访问事件日志
首先,确保运行 Web 应用程序的进程帐户(如果应用程序是模拟的,可以是线程身份)能构建事件源。为此,进程或线程身份必须要在建立下面的注册表项:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog
最低限度,任意模拟身份的 ASP.NET 进程身份都要设置下面的注册表项:
• 查询项值
• 设置项值
• 构建子项
• 枚举子项
• 通知
• 读
这些设置必须应用在上述项和子项。另一种方法是,您可在管理特权有效的情况下于安装时创建事件源。有关本方法的详细信息,请参阅模块 10 构建安全的 ASP.NET 网页和控件中的“审核和日志记录”。
使用 sandbox 方法
要使用 sandbox 方法处理事件日志记录代码,您必须创建一个包装程序集来封装事件日志访问。然后,将包装程序集安装在全局程序集缓存中,以便由代码访问安全性策略授予它完全信任。
• 构建使用 sandbox 方法的包装程序集来写入事件日志
1.
为事件日志代码创建程序集。配置程序集版本,赋予程序集强名称,使用“AllowPartiallyTrustedCallersAttribute”标记,如下所示:
[assembly:AssemblyVersion("1.0.0.0")]
[assembly:AssemblyKeyFile(@"..\..\eventlogwrapper.snk")]
[assembly:AllowPartiallyTrustedCallersAttribute()]
如果希望支持部分信任调用者,您必须使用“AllowPartiallyTrustedCallersAttribute”批注所有强名称程序集。只要强名称程序集中的代码被加载且 JIT 编译,都将抑制 .NET Framework 的隐式完全信任链接请求。
注意:AllowPartiallyTrustedCallersAttribute 在“System.Security”命名空间定义,因此必须使用“using”语句来引用此命名空间。
2.
请求适当的权限。
从严格意义上讲,请求适当权限并非必要,但却是比较好的做法。因为它允许管理员使用类似 Permview.exe 的工具来查看程序集的权限要求。由于部分信任调用者能访问事件日志程序集,所以此程序集不需要请求完全信任权限集。本例中的程序集仅在特定的计算机中写入事件日志,因此,仅需下列权限请求:
[assembly:EventLogPermissionAttribute(SecurityAction.RequestMinimum,
MachineName="",
PermissionAccess=EventLogPermissionAccess.Instrument)]
但是,如果程序集必须请求完全信任,请按如下方式请求无限制的权限:
[assembly:PermissionSet(SecurityAction.RequestMinimum, Unrestricted=true)]
3.
使用“Assert”语句包装事件日志调用,“Assert”语句可断言完全信任,使用匹配的“RevertAssert”可逆转断言结果。从严格意义上讲,使调用置于“finally”块的“RevertAssert”并非必要,但却是比较好的做法。下面的代码将文本“Writing to the event log”信息项写入应用程序日志:
try
{
string source = "Event Source";
string log = "Application";
string eventText = "Writing to the event log";
EventLogEntryType eventType = EventLogEntryType.Information;
//断言权限
EventLogPermission eventPerm;
eventPerm = new EventLogPermission(EventLogPermissionAccess.Instrument,
"");
eventPerm.Assert();
//检查是否存在源。
if(!EventLog.SourceExists(source))
{//项不存在,请将您的应用程序注册为源
EventLog.CreateEventSource(source, log);
}
//写入日志。
EventLog.WriteEntry(source, eventText, eventType);
}
catch(Exception ex)
{/*Handle exception*/}
finally
{
CodeAccessPermission.RevertAssert();
}
4.
使用下面的命令构建程序集,然后将它安装在 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 中的程序集由默认代码访问安全性策略授予完全信任。
5.
配置 Web 应用程序中级信任。将下面的内容添加到 Web.config 文件中,置于指向应用程序的 元素中。
6.
引用 ASP.NET Web 应用程序中的事件日志程序集。
由于强名称程序集一定在 GAC 中(不在 Web 应用程序的 \bin 目录中),如果您不在文件后使用代码,一定要将程序集添加到应用程序使用的程序集列表中。您可以使用下面的命令获得程序集的“PublicKeyToken”:
sn -Tp eventlogwapper.dll
注意:使用大写的 –T 参数。
然后,将下面的代码添加到 Machine.config 或 Web.config 文件:
注意:在包装程序集的连续重建过程中,您可能需要循环 ASP.NET 工作进程,因为安装在 GAC 中的包装程序集由 ASP.NET 进程缓存。通过循环 ASP.NET 工作进程 (Aspnet_wp.exe),您可运行 IISreset.exe 实用程序。
7.
保护调用“Assert”方法的代码。“Assert”调用意味着调用事件日志包装的所有代码都能与事件日志交互。要防止恶意代码调用事件日志包装并使用该包装填充事件日志,您可在调用“Asserrt”并更新中级信任策略文件以授予 Web 应用程序自定义权限之前发出自定义权限的完全权限请求。本解决方案需要一定量的开发工作。
有关如何开发自定义权限的详细信息,请参阅本指南的如何:创建自定义加密权限一节。
Web 服务
在默认情况下,中级信任策略授予 ASP.NET Web 应用程序有限的“WebPermission”。要能在 Web 应用程序中调用 Web 服务,您必须配置应用程序 元素的 originUrl 属性。
• 在中级信任 Web 应用程序中调用单个 Web 服务
1.
配置应用程序,使其按中级信任级别运行。
2.
使“originUrl”指向要调用的 Web 服务,如下所示:
“originUrl”值用在“System.Text.RegEx”正则表达式类的构造函数中,目的是匹配 Web 服务访问的 URL。这里的“RegEx”类用于连接“WebPermission”类。“.*”表示匹配所有“”开头的 URL。
“originUrl”属性在系统评估 ASP.NET 策略时使用。它向“$OriginHost$”替代参数赋予值。下面是 Web_mediumtrust.config 文件中的“WebPermission”定义:
class="WebPermission"
version="1">
如果未指定应用程序要访问的 Web 服务器,所有 Web 服务请求都将失败,并产生“SecurityException”。要调用本地 Web 服务器中的 Web 服务,请使用下列配置:
如果应用程序必须访问不同服务器中的多个 Web 服务,您必须自定义 ASP.NET 策略。因为在 Web.config 或 Machine.config 文件中的 元素中只能指定一个 originUrl。
• 在中级信任应用程序中调用多个 Web 服务
1.
将下面目录中的 Web_mediumtrust.config 文件复制到同一目录下名为“Web_mediumtrust_WebService.config”的文件中。
%windir%\Microsoft.NET\Framework\{version}\CONFIG
2.
查找“WebPermission”,然后为要访问的每个服务器添加 元素,如下所示:
如果使用 NetBIOS 名称、DNS 名称和/或 IP 地址调用 Web 服务,每个 URI 必须包含各自的 元素,如下所示:
3.
保存文件。
4.
更新应用程序的 Web.config 文件,使之指向新创建的策略文件。这要求创建新的信任级别,然后将它映射到新策略文件。接下来, 使用新级别配置应用程序的 元素。
下面的片段必须添加到 Web.config 文件中:
policyFile="web_mediumtrust_WebService.config"/>
使用默认凭据
您可能需要调用使用 Windows 身份验证的 Web 服务,然后通过代理凭据缓存指定身份验证凭据。例如:
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
在这种情况下,ASP.NET 应用程序要求“EnvironmentPermission”权限,即有“USERNAME”环境变量的读取权限。默认的中级信任策略将此权限授予 Web 应用程序。
在 ASP.NET 服务器端方案中,凭据从 ASP.NET 应用程序的线程或进程级令牌中获得。如果在桌面应用程序中使用“DefaultCredentials”,则要使用当前交互用户的令牌。请求“EnvironmentPermission”权限是一种风险缓解策略,主要目的是确保代码不能随意使用本地用户凭据,并将凭据公开在网络中。
注册表
在默认情况下,中级信任 Web 应用程序不被授予“RegistryPermission”。要配置应用程序访问注册表,您必须修改 ASP.NET 策略,然后将此权限授予应用程序;或开发必要的权限,其中包含使用 sandbox 方法的包装程序集。
sandbox 方法与前面 OLE DB 数据源和事件日志中描述的一样。
自定义策略
自定义策略最简单的方法是,基于中级信任策略文件创建自定义策略文件,配置应用程序使用自定义策略。自定义策略可将“RegistryPermission”权限授予应用程序。
• 创建自定义策略来允许注册表访问
1.
将下面目录中的 Web_mediumtrust.config 文件复制到同一目录下名为“Web_mediumtrust_Registry.config”的文件中。
%windir%\Microsoft.NET\Framework\{version}\CONFIG
通过复制并创建自定义策略文件,可避免直接更改 Web_mediumtrust.config 文件。直接更改默认的中级信任文件将影响计算机中所有配置为中级信任的应用程序。
2.
查找 元素,添加下面的内容来注册“RegistryPermission”类:
Description="System.Security.Permissions.RegistryPermission,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
3.
查找 ASP.NET 权限集,按如下方法将无限制的“RegistryPermission”添加到权限集:
4.
保存文件。
5.
更新 Machine.config 文件来创建映射到新策略文件的新信任级别。
policyFile="web_mediumtrust_Registry.config "/>
6.
更新应用程序的 Web.config 文件来配置应用程序的 级别。
返回页首
小结
代码访问安全性是一种资源约束安全模型,主要用于隔离应用程序。您可以配置应用程序按不同的部分信任级别运行。信任级别决定了授予 ASP.NET Web 应用程序或 ASP.NET Web 服务的权限,也决定了可访问的资源类型和执行的其他特权操作类型。注意:所有的资源访问最终都要服从于操作系统安全性。
建议的隔离模型使用 Windows Server 2003 中的 IIS 6.0 应用程序池。除了可提供代码访问安全性外,还可提供进程级隔离。在 Windows 2000 中,隔离只能通过代码访问安全性和独立线程身份实现。
如果要迁移应用程序,使之按部分信任级别运行,常需要一定量的重新工程处理。如果应用程序要访问的资源是部分信任级别不允许访问的,或应用程序调用的强名称不包含 APTCA,您可能需要重新工程处理。此时,您可以在单独的包装程序集中使用 sandbox 特权资源访问。在有些方案中,您可以创建并使用自定义策略文件,尽管这取决于 Web 服务器的安全策略。
最佳的做法是,将资源访问代码置于单独的程序集,并避免将这种代码置于 .aspx 文件或文件背后的代码中。使用单独的程序集可将代码访问安全性策略应用到独立于 Web 应用程序的程序集,它允许您开发使用 sandbox 方法的信任代码来执行资源访问。
返回页首
其他资源
有关详细信息,请参阅下列资源:
• Security in .NET:MSDN Magazine 上的“The Security Infrastructure of the CLR Provides Evidence, Policy, Permissions, and Enforcement Services”,其网址是:http://msdn.microsoft.com/msdnmag/issues/02/09/SecurityinNET/default.aspx(英文)。
• Security in .NET:MSDN Magazine 上的“Enforce Code Access Rights with the Common Language Runtime”,其网址是:(英文)。