ASP.NET 4 应用程序中的代码访问安全性
代码访问安全性 (CAS) 是 ASP.NET 用于对执行代码的能力强制进行约束的 .NET Framework 安全机制(“沙盒”)。 自 ASP.NET 1.1 起,ASP.NET 使用信任级别概念实现了代码访问安全性。
本主题介绍 CAS 在 ASP.NET 4 中的工作原理,尤其重点介绍了 CAS 自早期版本进行了哪些更改。 如果您刚刚接触 ASP.NET,则可能不会对这些更改感兴趣。 不过,本主题包括有关当前版本 ASP.NET 中的 CAS 工作原理的信息,这可能会影响您设计新应用程序的方式。
本主题讨论以下主题:
为何不再使用 CAS 策略级别,以及这会对典型方案(如让部分信任 ASP.NET 应用程序从 UNC 共享运行)有何影响。
如何自定义 ASP.NET 4 中的 CAS 行为。
使受信任代码可以在 ASP.NET 4 中使用 CAS 时的兼容性问题。
本主题假定您了解 .NET Framework CAS 和 ASP.NET 信任级别。 有关这些主题的信息,请参见以下文档:
How to: Use Medium Trust in ASP.NET 2.0(如何:在 ASP.NET 2.0 中使用中等信任)
Using Code Access Security with ASP.NET(将代码访问安全性用于 ASP.NET)
Blog series about CAS policy and the CLR, by Shawn Farkas(由 Shawn Farkas 撰写的有关 CAS 策略和 CLR 的系列博客)
本主题包含以下信息:
ASP.NET 4 代码访问安全性模型概述
同类应用程序域
条件 APTCA
安全透明度以及它在 ASP.NET 4 中的工作原理
ASP.NET 4 代码访问安全性模型概述
在 ASP.NET 4 中,相对于 ASP.NET 3.5 及更早版本,对 CAS 进行了多个基本更改,包括以下这些:
默认情况下,ASP.NET 4 部分信任应用程序域是同类的。 这会针对在部分信任应用程序域中运行的代码产生一组受约束的可能权限集。 这也意味着,应用程序域信任边界自身将与部分信任授予集关联。 在同类应用程序域中,安全策略不与计算机级别、用户级别或企业级别 CAS 策略相交。
备注
新的同类应用程序域模型需要一组声明性 ASP.NET 信任策略文件,这些文件与早期版本 ASP.NET 中使用的策略文件略有不同。因此,安装 ASP.NET 4 后,计算机将包含两组 ASP.NET 部分信任策略文件。新 CAS 模型使用其中一组,而另一组在应用程序配置为使用 ASP.NET 4 之前的 CAS 模型时使用。
在早期版本的 ASP.NET 中,几乎所有公共 ASP.NET 相关类上都使用了 AspNetHostingPermission 特性,以防止在非 Web 部分信任环境中使用 ASP.NET 类型。 例如,AspNetHostingPermission 特性的存在可防止在部分信任 ClickOnce 应用程序中使用大多数 ASP.NET 类。 (有关 ClickOnce 应用程序中 CAS 的信息,请参见 ClickOnce 应用程序的代码访问安全性。)ASP.NET 4 使用另一种称为条件 APTCA(基于 AllowPartiallyTrustedCallersAttribute 类型)的 CAS 技术实现相同的结果,而不是依赖于 AspNetHostingPermission 特性。 因此,已从大多数 ASP.NET 类型和成员中移除了 AspNetHostingPermission 特性。
在 ASP.NET 4 中,许多系统程序集已更新为使用 CLR 安全透明度模型。 ASP.NET 4 中的透明度模型与在 Silverlight 中使用的透明模型十分相似。 有关代码透明度的更多信息,请参见安全透明的代码。
如果您依赖于使用 caspol.exe 之类的工具创建的自定义 CLR CAS 策略,则会看到这些更改的效果。 这些更改也会影响具有以下特点的部分信任 Web 应用程序:依赖于部署在 GAC 中的程序集,以便仅当 ASP.NET 或 .NET Framework 代码在调用堆栈中处于活动状态时才执行特权操作。 以下各节讨论了这些 CAS 更改。
同类应用程序域
此节介绍同类应用程序域。 它讨论了自 ASP.NET 2.0 以来对同类应用程序域产生的行为更改。 还讨论了为在同类应用程序域中运行代码,可设置的兼容性选项以及可进行的代码更改。
减少了可能的权限集数
同类应用程序域是部分信任应用程序域,这些域将定义共享权限集以便运行代码。 在 ASP.NET 4 中承载的同类应用程序域中,可加载的代码将与两个权限集之一关联。 代码要么以完全信任方式运行(GAC 代码始终以完全信任方式运行),要么通过由当前 trustLevel 设置定义的部分信任权限集运行。 (有关更多信息,请参见 securityPolicy 的 trustLevel 元素(ASP.NET 设置架构)。)
备注
ASP.NET 4 应用程序域默认为完全信任。ASP.NET 4 中的同类行为仅在 trustLevel 元素的 name 特性设置为 Full 以外的值之后才生效。
此行为不同于早期版本 ASP.NET 中的部分信任应用程序。 在早期版本中,可以创建多个权限集,其中每个权限集都具有不同的授予集和不同的成员资格条件。 因为难以处理类似这些的混合权限方案,所以在 .NET Framework 4 中引入了同类应用程序域。 难以创建其中每个权限集都具有不同权限级别的多个权限集,然后证明在考虑可以运行代码的所有条件后实际强制实施了不同的权限级别。 例如,代码可以在反射下运行,完全信任代码可以代表部分信任调用方运行其他完全信任代码,诸如此类。 权限集必须考虑所有这类条件。 同类应用程序域通过减少可能的结果,极大简化了 CAS 决策。 代码要么具有完全信任,要么具有单个定义完善的部分信任权限集。 对于 ASP.NET,定义完善的部分信任权限集是应用于指定 ASP.NET 信任级别的权限集。
对于尝试在同类应用程序域中加载的代码,不存在第三种可能的状态。 (CLR 不会将此视为单独权限集)。第三个权限集是空权限集,这在所有 ASP.NET 部分信任配置文件中都定义为 Nothing 权限集。 计算为 Nothing 权限集的所有代码都会视为无法加载。 因此,将具有 Nothing 权限集的程序集加载到同类应用程序域中的任何尝试都会导致 SecurityException 异常。
仅应用 ASP.NET 部分信任策略
同类应用程序域的部分信任权限集仅由负责创建应用程序域的主机建立。 在 ASP.NET 4 中,这意味着部分信任权限集仅由部分信任配置文件(位于 .NET Framework 安装的 CONFIG 子目录中)的内容定义。 默认情况下,ASP.NET 4 部分信任应用程序域的 ASP.NET 策略信息不再与企业、计算机或用户 CAS 策略设置重叠。
全局 CAS 策略信息(开发人员以前使用 caspol.exe 这类工具或 Mscorcfg.msc MMC 配置工具管理的策略)将不再对 ASP.NET 4 同类应用程序域具有任何影响。 (您可将 ASP.NET 配置为使用早期 CAS 模型,这类模型中的 ASP.NET 设置与企业、计算机和用户策略相交。 这一旧行为将在后面一节中进行说明。)
最明显的更改是针对 UNC 承载的部分信任 ASP.NET 4 应用程序。 在早期版本,您必须使用 caspol.exe 将 UNC 共享提升到完全信任,才能允许 ASP.NET 部分信任策略生效。 这是因为在早期版本的 ASP.NET 中,默认计算机级别 CLR CAS 策略会首先生效。 因此,UNC 承载的应用程序具有与 Intranet 区域相关联的受约束权限集。 因为 ASP.NET 4 部分信任应用程序域仅通过 ASP.NET 策略文件建立策略,所以 Web 应用程序的物理位置不再对与部分信任应用程序相关联的权限集具有任何影响。
此更改的副作用可通过以下方案进行阐释:管理员需要锁定 Web 服务器以在默认情况下拒绝对所有托管代码的执行权限,然后为所选 ASP.NET 应用程序授予执行权限。 在以前版本的 ASP.NET 中,这需要一个鲜为人知的解决方法,如知识库文章 FIX: Error message when you try to run an ASP.NET 2.0 Web application if you do not associate the My_Computer_Zone code group with the "full trust" permission set: "Server Application Unavailable(修复:当您尝试在未将 My_Computer_Zone 代码组与“完全信任”权限集关联的情况下运行 ASP.NET 2.0 Web 应用程序时出现错误消息:“服务器应用程序不可用”)中所述。 在 ASP.NET 4 中,管理员可以通过下列这些步骤锁定 Web 服务器以拒绝或授予执行权限:
创建一个其策略文件将所有代码映射到 Nothing 权限集(空权限集)的自定义 ASP.NET 信任级别,然后将所有 ASP.NET 应用程序配置为在默认情况下使用该信任级别。 (此操作在根 Web.config 文件中进行。)
有选择性地将各个 ASP.NET 应用程序与向托管代码授予执行权限(以及所需的任何其他权限)的内置或自定义信任级别相关联。 对于计算机级别强制,可以在根 Web.config 文件中使用 location 元素有选择性地分配信任级别。
信任策略文件的位置和命名约定
CAS 策略文件的位置和命名约定与早期版本 ASP.NET 中相同。 默认信任级别为 Full、High、Medium、Low 和 Minimal。 定义 High 到 Minimal 的部分信任权限集的策略文件全都位于 .NET Framework 安装目录的 CONFIG 子目录中。
这些策略文件使用以下模式进行命名:
web_[trustlevelname]trust.config
例如,Medium 信任的部分信任权限集位于名为 web_mediumtrust.config 的文件中。
ASP.NET 4 的信任策略文件中的更改
在很大程度上,ASP.NET 4 CAS 策略文件中的信息与以前版本中的策略文件中的信息相同。 但是,.NET Framework 3.5 和 .NET Framework 4 功能略微增加了一些内容。 与同类应用程序域相关联的部分信任权限集的名称为 ASP.Net。 此外,默认情况下将从命名 ASP.Net 权限集向位于 Web 应用程序目录结构或代码生成目录结构中的所有代码授予权限。
与以前版本的部分信任策略文件相比,进行了两个更改:
在每个 ASP.NET 4 CAS 策略文件的末尾,不再存在 CodeGroup元素,该元素将完全信任映射到 Microsoft 签名密钥和 ECMA 签名密钥。 这些条目已在 ASP.NET 4 中移除,因为这些条目是从早期版本的旧功能,当时并不总是隐式假定 GAC 具有完全信任。
SecurityPermission 特性的 Assertion 部分已从所有 ASP.NET 4 CAS 策略文件中移除。 CLR 在 .NET Framework 4 中进行的基本更改是部分信任代码无法断言权限。 这意味着部分信任代码将失败,即使它尝试断言其已具有的权限也是如此。
部分信任的范围
同类应用程序域意味着 ASP.NET 4 应用程序域边界是部分信任的。 当应用程序以部分信任方式运行时,安全要求会导致堆栈审核。 将针对要求的权限计算堆栈上的所有代码。 在 ASP.NET 3.5 以及更早版本的应用程序域中,代码路径通常会导致堆栈审核一直到达应用程序域边界。 因为早期版本 ASP.NET 4 中的应用程序域边界是隐式完全信任的,所以某些代码路径的堆栈审核会成功。 在 ASP.NET 4 同类应用程序域中,会针对当前对应用程序域生效的部分信任权限集计算到达应用程序域边界的任何堆栈审核。
现在应用程序域边界本身是部分信任的,这一事实是最常见的 CAS 更改,这通常要求您更改完全信任代码,才能使其在 ASP.NET 4 中正常运行。 例如,ASP.NET 开发团队必须在许多内部代码路径上添加有针对性的安全断言,才能禁止安全要求并防止其向上冒泡到应用程序域边界。 如果开发团队尚未执行此操作,则页编译这类基本任务将失败,因为对此类操作的安全要求(例如,用于编译的文件 I/O 权限)在与信任级别(如 Medium)的部分信任权限集进行比较时将失败。
ASP.NET 中存在扩展性点,这些点可能会导致在只有 ASP.NET 代码位于堆栈中时,加载和运行完全信任的代码。 在这些情况下,当 ASP.NET 调入实现某种类型扩展性点的自定义类型时,最初只有 ASP.NET 代码位于堆栈中。 如果自定义类型是完全信任的(仅当类型部署在 GAC 中时才会出现这种情况),则结果是整个调用堆栈由完全信任的代码组成。 在同类应用程序域中,如果完全信任扩展性类型中的任意代码触发了某个安全要求,则该要求最终将到达应用程序域边界。 当对部分信任权限集执行安全检查时,该要求会失败。
下面是可能存在此情况的某些 ASP.NET 扩展性点的列表:
自定义 HTTP 处理程序。 在管道的处理程序执行阶段调用的自定义处理程序。
自定义 HTTP 模块。 自定义 HTTP 模块会在为其注册该模块的任何管道事件期间进行调用。
自定义生成提供程序和表达式生成器。 当 ASP.NET 分析和编译可执行内容(如 .aspx 文件)时,会调用这些类型。
角色管理器提供程序。 可以在管道中的 AuthorizeRequest 事件期间调用自定义提供程序。
配置文件提供程序。 可以在 EndRequest 事件期间调用自定义提供程序以自动保存配置文件数据。
运行状况监视提供程序。 可以随时调用自定义提供程序以存储累积的运行状况监视数据。
一个简单的自定义 HTTP 处理程序示例阐释了 CAS 行为的更改。 在下面的示例中,处理程序代码尝试读取位于 C:\ 驱动器的根目录中的文本文件。
Public Class CustomHandler
Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext)
Dim data As String = File.ReadAllText("c:\testfile.txt")
context.Response.Write(data)
End Sub
Public Sub New()
End Sub
Public ReadOnly Property IsReusable() As Boolean
Get
Return False
End Get
End Property
End Class
public class CustomHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string data = File.ReadAllText("c:\\testfile.txt");
context.Response.Write(data);
}
public CustomHandler() { }
public bool IsReusable { get { return false; } }
}
如果处理程序进行了签名,通过 AllowPartiallyTrustedCallersAttribute 特性进行了标记并部署在 GAC 中,则在 ASP.NET 3.5 或更早版本的中等信任应用程序中使用该处理程序时,这些代码会成功执行。 为此示例选择了中等信任,因为在中等信任中,部分信任权限集只允许对应用程序的目录结构读取/写入文件 I/O。 完全信任的代码(如示例处理程序)能够在 ASP.NET 3.5 以及更早版本中访问其他文件位置。 这是因为在该处理程序运行时,只有完全信任的代码位于堆栈中,并且应用程序域边界本身是完全信任的。 因此,处于完全信任的应用程序域边界隐式满足了 ReadAllText 调用的文件 I/O 要求。
但是,如果相同的处理程序代码在中等信任 ASP.NET 4 应用程序中使用,则会失败,因为对 ReadAllText 的调用会导致在对文本文件进行读取访问方面的文件 I/O 要求。 该文件 I/O 要求将导致最终到达应用程序域边界的堆栈审核。 在 ASP.NET 4 中,应用程序域边界与中等信任权限集相关联,并且该权限集不授予对 C:\ 驱动器的根目录的访问权限。 因此,该文件 I/O 要求将失败。
对于 ASP.NET 4,您必须禁止堆栈审核。 为此,请对 ProcessRequest 方法使用 FileIOPermission 特性的 SecurityAction.Assert 特性。 下面的示例演示如何使用 FileIOPermission 特性实现此用途。
[Visual Basic]
Public Class CustomHandler
Implements IHttpHandler
<FileIOPermission(SecurityAction.Assert, Read = "c:\testfile.txt")> _
Public Sub ProcessRequest(ByVal context As HttpContext)
Dim data As String = File.ReadAllText("c:\testfile.txt")
context.Response.Write(data)
End Sub
Public Sub New()
End Sub
Public ReadOnly Property IsReusable() As Boolean
Get
Return False
End Get
End Property
End Class
[C#]
public class CustomHandler : IHttpHandler
{
[FileIOPermission(SecurityAction.Assert, Read = "c:\\testfile.txt")]
public void ProcessRequest(HttpContext context)
{
string data = File.ReadAllText("c:\\testfile.txt");
context.Response.Write(data);
}
public CustomHandler() { }
public bool IsReusable { get { return false; } }
}
您可以使用声明性断言(如示例中所示)或编程断言。 最好做法是以声明方式断言使代码块运行所需的最少权限。 虽然随处添加不受限制的安全断言可能看上去是一种简单的解决方案,但不应使用该方法。 新同类应用程序域行为会导致安全失败,这些行为的设计要求您分析完全信任代码并了解完全信任代码需要的特权操作。 因而可以有选择性地断言重新启用完全信任代码所需的最少权限集。
将 ASP.NET 4 应用程序配置为使用 ASP.NET 2.0 CAS 模型
可以将 ASP.NET 4 应用程序配置为使用 ASP.NET 1.0 和 ASP.NET 2.0 CAS 行为。 在 ASP.NET 4 中,trust 元素提供了一个新的 legacyCasModel 特性,该特性默认情况下设置为 false。 通过此特性设置为 true,可以将 ASP.NET 4 应用程序配置为使用早期版本中的大多数(尽管不是全部)ASP.NET CAS 行为。
当 LegacyCasModel 特性设置为 true 时,将出现以下行为:
部分信任应用程序域边界使用完全信任。 这意味着对于完全信任代码执行时只有完全信任代码位于堆栈中这种情况,您不必使用断言来禁止安全要求。
为 .NET Framework 4 定义的企业、计算机和用户 CAS 策略设置与 ASP.NET CAS 策略相交。 这意味着使用 .NET Framework 4 caspol.exe 或 Mscorcfg.msc 创建的任何自定义权限都将生效。
备注
因为 .NET Framework 4 的基本安全策略文件和 caspol.exe 工具所在的目录不同于 .NET Framework 2.0 的目录,所以必须使用 .NET Framework 4 版本的 caspol.exe 为 .NET Framework 4 重新创建已为 .NET Framework 2.0 创建的任何自定义安全策略。
您可以指定应用于不同程序集的多个自定义权限集。
以下 CAS 相关行为不会更改,即使在旧 CAS 模式下也是如此:
ASP。 NET 4 程序集仍标记为条件 APTCA。 (条件 APTCA 将在本主题后面进行介绍)。条件 APTCA 不能还原为旧模式,因为这涉及到从大多数公共 ASP.NET 4 API 中移除 AspNetHostingPermission 特性。 没有一种高效方法可使该权限在 ASP.NET 公共 API 运行于旧 CAS 模式下时应用于这些 API,而在程序集运行于新 CAS 模型中时不应用。
不再允许部分信任代码断言任何权限。 以前被授予部分信任的代码可以调用 Assert 方法并成功断言已向部分信任代码授予的任何权限。 在 .NET Framework 4 中,无论将哪种 CAS 模型用于 ASP.NET 应用程序,都不再允许部分信任代码执行安全声明。
为了对在旧 CAS 模型中应用的权限集和在新 CAS 模型中应用的单个权限集加以区分,当 trust 元素的 LegacyCasModel 特性设置为 true 时,ASP.NET 4 将从另一组部分信任配置文件中读取 CAS 策略。 对于针对 ASP.NET 内置信任级别而存在的每个信任策略文件,都存在两个版本的文件。 ASP.NET 为新 CAS 模型读取一个版本,为旧 CAS 模型读取另一个版本。 例如,对于中等信任,当 ASP.NET 4 在旧模式下运行时,它会读取名为 legacy.web_mediumtrust.config 的策略文件。 请注意,该文件名的开头是“legacy”。 与内置 ASP.NET 信任级别一样,ASP.NET 4 也对所有 CAS 策略文件使用相同的命名约定。 新旧 CAS 策略文件之间的主要差别是,旧文件包括引用 Microsoft 签名密钥和 ECMA 签名密钥的 CodeGroup 定义。
因为您可以将应用程序配置为使用旧 CAS 模型,因此对于现有应用程序,可能需要将 LegacyCasModel 选项设置为 true,从而避免进行任何更改。 但是,旧选项的存在主要是为了简化从现有应用程序到 ASP.NET 4 CAS 模型的转换,了解这一点十分重要。 将来,CLR 和 ASP.NET 团队都会将重点放在新 CAS 模型的设计和编码上。
Silverlight 2 是首个移到新模型的 .NET Framework 功能区域。 .NET Framework 的目标是移动所有桌面和服务器部分信任方案,以便在新 CAS 模型上运行。 因此,建议您将精力放在重新使应用程序可以在新 CAS 模型中正常工作上。 同样,以前依赖于 caspol.exe 和 Mscorcfg.msc 的管理员也应改为依赖于自定义 ASP.NET 部分信任策略文件和权限分配。
在 ASP.NET 4 CAS 模型中自定义权限集分配
尽管 ASP.NET 4 同类应用程序域限制代码只能以完全信任权限或指定的 ASP.NET 部分信任权限集运行,不过开发人员和管理员可以影响权限集与程序集的关联过程。 通过以下几种方法,可以自定义将权限集与一段运行代码相关联的过程:
可以为单个信任级别自定义部分信任策略文件。 (此方法在早期版本的 ASP.NET 中是可行的。)
可以静态配置 ASP.NET 4 完全信任程序集。
可以使用 ASP.NET 4 HostSecurityPolicyResolver 类型来通过受限方式访问 CLR HostSecurityManager 类的功能。
其中的前两种方法用于以声明方式进行自定义,第三种方法用于通过代码进行自定义。
为信任级别自定义策略文件
修改 ASP.NET 部分信任策略文件的第一种方法与早期版本 ASP.NET 中的方法相同:可以在 ASP.NET 命名权限集中修改权限集。 也可以添加多个具有自定义成员资格条件的 CodeGroup 定义。 如前面所述,必须在 web_mediumtrust.config 之类的部分信任策略文件中进行新的 CAS 自定义。 当 trust 元素的 LegacyCasModel 特性设置为 true 时,将分析并使用文件名以“legacy”开头的文件。
对于 ASP.NET 4,所有自定义 CodeGroup 定义必须映射到三个可能的权限集之一: FullTrust、ASP.Net (即部分信任权限集)或 Nothing。 因为 ASP.NET 4 部分信任应用程序域默认情况下是同类的,所以自定义策略条目必须计算为一组受约束的权限集。 虽然使用 ASP.NET 4 CAS 模型时似乎可以定义不同的命名权限集,但是计算为 FullTrust、ASP.Net 或 Nothing 以外的权限集的任何代码都将导致运行时 SecurityException 异常。 这表明 CLR 无法识别计算后的权限集。
FullTrust 权限集表示代码以完全信任方式运行。 ASP.Net 权限集是命名的部分信任权限集,通常用于部分信任应用程序域。 如前面所述,Nothing 不是可由 CLR 识别的实际权限集;而是空权限集。 如果 CLR 确定程序集与空权限集相关联,则 CLR 将引发 SecurityException 异常,并且 CLR 不会加载程序集。
此外,ASP.NET 4 还允许您使用 trust 元素的 PermissionSetName 特性更改 ASP.Net 权限集的名称。 您可以为 PermissionSetName 特性设置不同的名称。 在运行时,ASP.NET 4 将在部分信任策略文件中搜索同名的 PermissionSet 元素。 该命名权限集随后将用作同类应用程序域的部分信任权限集。 不一定必须执行此操作。 但是,增加了将部分信任权限集的名称更改为 ASP.Net 之外的某一名称的能力,以适应将自己的命名权限集定义为不同于 ASP.NET 默认权限集的某一实体的宿主环境(例如 SharePoint)。 (请记住,在新 CAS 模型中,不能再具有多个定义部分信任权限的命名权限集。)虽然您可以将部分信任权限集的名称更改为 ASP.Net 之外的某一名称,但仍只能有一个部分信任权限集对应用程序生效。
指定将被授予完全信任的程序集
第二个声明性策略自定义是 ASP.NET 4 的新增功能,使您可以显式建立将始终被授予完全信任的程序集标识的列表。 securityPolicy 配置包含一个新的子 fullTrustAssemblies 配置节。 FullTrustAssembliesSection 节是一个支持添加、移除和清除操作的标准集合,您可以在其中指定将在运行时被授予完全信任的一个或多个程序集标识。 下面的示例演示 fullTrustAssemblies 配置节。
<system.web>
<securityPolicy>
<fullTrustAssemblies>
<add assemblyName="MyCustomAssembly"
version="1.0.0.0"
publicKey="a 320 hex character representation
of the public key blob used with a
signed assembly"
/>
</fullTrustAssemblies>
</securityPolicy>
</system.web>
fullTrustAssemblies 元素中的每个条目通过程序集名称和程序集版本以及一个 320 个字符的字符串(即签名密钥公开的半部分的十六进制字符表示形式)来标识程序集。
备注
将来,新 .NET Framework 程序集可能会使用 2048 位签名密钥。如果发布了使用 2048 位签名密钥的新程序集,则会产生长度为 576 个字符的十六进制字符串。
不在定义中指定任何程序集位置。 各宿主环境(如 ASP.NET 4)负责查找和加载程序集。 如果加载的程序集与 fullTrustAssemblies 中的某个 add 元素所包含的信息匹配,则授予该程序集完全信任。
您应对未在 GAC 中部署但旨在始终以完全信任方式运行的程序集使用 fullTrustAssemblies。 因为 fullTrustAssemblies 中列出的程序集可以在配置层次结构的任意位置(从根 Web.config 文件到各应用程序级别 Web.config 文件)进行自定义,所以与在部分信任策略文件中使用成员资格条件和代码组相比,使用此设置对于授予完全信任更加方便且更加灵活。 您可以通过为不同应用程序指定不同信息,为各应用程序自定义 fullTrustAssemblies 列表。 可以使用 location 元素在应用程序级别 Web.config 文件或根 Web.config 文件中实现这一点。
在创建部分信任应用程序域时会立即建立完全信任程序集组。 因此,如果部分信任策略文件包含的信息对于在 fullTrustAssemblies 元素中列出的某个程序集产生了不同授予集,则将忽略这些信息并向该程序集授予完全信任。
以编程方式自定义权限
您可以通过创建 ASP.NET 4 HostSecurityPolicyResolver 类型的自定义实现,以编程方式更改权限集与程序集的关联。 在运行时,ASP.NET 4 使用其自己的 CLR HostSecurityManager 类型实现。 每次加载程序集时,CLR 都会调用 HostSecurityManager 对象。 HostSecurityManager 属性的功能之一是返回应与指定程序集关联并用于一组证据的 PermissionSet 对象。 ASP.NET 4 使您可以自定义此过程,方法是在每次 CLR 向 ASP.NET 4 请求权限集决策时都调用自定义 HostSecurityPolicyResolver 对象。
可以使用 trust 元素的 HostSecurityPolicyResolverType 特性来配置自定义 HostSecurityPolicyResolver 对象。 如果 ASP.NET 4 确定为应用程序配置了自定义 HostSecurityPolicyResolver 对象,则会在每次 CLR 请求权限集决策时都调用自定义解析程序的 ResolvePolicy 方法。 但是与 HostSecurityManager 对象不同,HostSecurityPolicyResolver 对象只能向 ASP.NET 4 返回一组受约束的可能决策。 ResolvePolicy 方法返回值必须是 HostSecurityPolicyResults 枚举中的以下值之一:
DefaultPolicy. 这指定 ASP.NET 4 应使用其自己的逻辑来为程序集确定适当的权限集。 对于不希望 HostSecurityPolicyResolver 对象进行有关权限集的决策的程序集,应返回 DefaultPolicy。 如果返回 DefaultPolicy,可使 ASP.NET 根据当前 ASP.NET 信任级别的部分信任策略文件中定义的声明性代码组和成员资格条件确定程序集的权限授予集。
FullTrust. 应向程序集授予完全信任。
AppDomainTrust. 应向程序集授予与应用程序域相关联的部分信任权限集。 通常这意味着将向程序集授予命名 ASP.Net 权限集中定义的权限。
None. 程序集的权限集将设置为 Nothing 权限集,这是一个
因为 HostSecurityPolicyResolver 基类对不受限制的安全权限具有继承要求,并且自定义 HostSecurityPolicyResolver 对象必须可加载,而无需其他 HostSecurityPolicyResolver 对象建立完全信任,所以 HostSecurityPolicyResolver 类的具体实现应始终进行签名并部署在 GAC 中。
下面的示例演示一个自定义 HostSecurityPolicyResolver 对象,该对象向从特定目录加载的所有程序集授予完全信任。 对于在磁盘上特定位置(不是 GAC)中添加编译的程序集并希望该位置中的所有文件自动以完全信任方式运行的组织,这可能是一种方案。 若要使 ASP.NET 应用程序能够从 Web 应用程序目录结构外部加载程序集,必须添加将程序集标识与不同物理磁盘位置相关联的显式程序集绑定重定向。
[Visual Basic]
Public Class MyCustomResolver
Inherits HostSecurityPolicyResolver
Public Overloads Overrides Function ResolvePolicy(ByVal evidence _
As Evidence) As HostSecurityPolicyResults
Dim urlEvidence As Url = evidence.GetHostEvidence(Of Url)()
If (urlEvidence IsNot Nothing) AndAlso _
(urlEvidence.Value.StartsWith("file:///C:/FullTrustExample_HSPR.dll")) Then
Return HostSecurityPolicyResults.FullTrust
End If
' Specify that ASP.NET should perform its own logic.
Return HostSecurityPolicyResults.DefaultPolicy
End Function
End Class
public class MyCustomResolver : HostSecurityPolicyResolver
{
public override HostSecurityPolicyResults
ResolvePolicy(Evidence evidence)
{
Url urlEvidence = evidence.GetHostEvidence<Url>();
if ( (urlEvidence != null) &&
(urlEvidence.Value.StartsWith("file:///C:/FullTrustExample_HSPR.dll"))
)
return HostSecurityPolicyResults.FullTrust;
// Specify that ASP.NET should perform its own logic.
return HostSecurityPolicyResults.DefaultPolicy;
}
}
条件 APTCA
在版本 4 之前的 .NET Framework 版本中,许多完全信任的程序集(包括 ASP.NET 程序集)通过 AllowPartiallyTrustedCallersAttribute (APTCA) 特性进行标记。 此特性使部分信任调用方可以访问在以此方式标记的程序集中定义的公共类型和成员。 在 .NET Framework 4 中,CLR 包含 APTCA 的一个变体,称为“条件 APTCA”。(条件 APTCA 的简短表示法为 C APTCA。)条件 APTCA 使通过 APTCA 特性标记的程序集只能在特定宿主环境中保留 APTCA 特征。 因此,条件 APTCA 使 ASP.NET 4 可以更容易地控制调用方恰好在哪些部分信任主机环境中能够成功调用公共 ASP.NET 4 API。
条件 APTCA 的工作原理
部分信任主机环境和完全信任的程序集在使条件 APTCA 正常工作方面都会发挥作用。 权限集十分重要的部分信任主机环境可以向 CLR 提供应始终采用 APTCA 设置的程序集列表。 对于应仅在特定主机环境中才启用其 APTCA 特征的完全信任的程序集,这些程序集使用程序集级别 APTCA 特性的以下变体指出这一点:
[assembly: AllowPartiallyTrustedCallers(PartialTrustVisibilityLevel=NotVisibleByDefault)]
在运行时,如果要求 CLR 加载标记为条件 APTCA 的程序集,则 CLR 将检查由主机环境提供的有效条件 APTCA 程序集列表。 如果程序集位于该列表中,则 CLR 将处理该程序集中的所有公共公开的代码,如同程序集在早期版本的 .NET Framework 中通过 APTCA 特性进行了标记一样。
如果条件 APTCA 程序集不在主机环境的应视为 APTCA 的程序集列表中,则该程序集仍会加载,但没有其 APTCA 特征。 此类程序集中部分信任用户代码的公共 API 的实际可用性将因程序集是否 100% 安全透明而异。 也就是说,实际可用性取决于程序集是否通过程序集级别 SecurityTransparentAttribute 特性进行标记。 (ASP.NET 4 中的安全透明度在本主题的后面一节中进行介绍。)
总之,ASP.NET 4 中的公共 API 可以通过以下方式之一采取行为:
对于大多数 ASP.NET 程序集,所有公共 API 都对部分信任调用方不可用。 实际上,这可以防止在 Web 应用程序以外的任何部分信任环境中使用 ASP.NET 4 中的多数公共 API。
一些标记为 100% 安全透明的 ASP.NET 程序集仍可从部分信任调用方进行调用。 但是,如果这些程序集中的代码路径最终到达 ASP.NET 代码库的其余部分,则调用将失败。 结果与以前版本的 ASP.NET 中的行为相同,略微不同的是对 ASP.NET 4 程序集中 API 的调用会在失败之前继续进行。
请注意以下有关标记为安全透明的程序集的内容:
在程序集级别,只有两个标记为安全透明的 ASP.NET 程序集:System.Web.DynamicData.dll 和 System.Web.RegularExpressions.dll。
在 ASP.NET 4 中不会将 System.Web.Routing.dll 视为 100% 安全透明,因为在早期版本 ASP.NET 中的该程序集中定义的所有类型都已移动到 System.Web.dll 中。 实际上,在 ASP.NET 4 中,System.Web.Routing.dll 是仅包含元数据的程序集。
在 ASP.NET 4 中,条件 APTCA 特性变体位于以下程序集中:
System.Web.dll
System.Web.Extensions.dll
System.Web.DynamicData.dll
System.Web.DataVisualization.dll
System.ComponentModel.DataAnnotations.dll
System.Web.ApplicationServices.dll。 此程序集是 ASP.NET 4 中新增的。
System.Web.Abstractions.dll。 此程序集中的类型已移动到 ASP.NET 4 的 System.Web.dll 中。
System.Web.Routing.dll。 此程序集中的类型已移动到 ASP.NET 4 的 System.Web.dll 中。
条件 APTCA 与 ASP.NET 宿主权限特性
通过条件 APTCA,实际上已从 ASP.NET 4 中 99% 的公共 API 中移除了 AspNetHostingPermission 特性。 ASP.NET 4 中的某些位置仍使用 AspNetHostingPermission 特性,但仅限该权限的用途真正有意义的位置。 在所有其他位置,都已不再出现 AspNetHostingPermission 特性的以下两种用法:
<AspNetHostingPermission(SecurityAction.LinkDemand,
Level=AspNetHostingPermissionLevel.Minimal)>
<AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level=AspNetHostingPermissionLevel.Minimal)>
[AspNetHostingPermission(SecurityAction.LinkDemand,
Level=AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level=AspNetHostingPermissionLevel.Minimal)]
这些权限定义在早期版本 ASP.NET 中使用,以防止在非 Web 部分信任环境中加载 ASP.NET 程序集。 相关的最大环境是加载到浏览器(例如 Microsoft Internet Explorer 和 Mozilla Firefox)中的部分信任托管控件和托管应用程序。 使用条件 APTCA 可有效地实施相同的保护,因为 ClickOnce 应用程序和基于浏览器的托管控件没有将要进行处理的任何条件 APTCA 程序集定义为为完全 APTCA。
自定义 ASP.NET 4 条件 APTCA 列表
如前所述,各个主机环境可以向 CLR 提供应保留 APTCA 特征的条件 APTCA 程序集列表。 ASP.NET 4 应向 CLR 提供包含所有 ASP.NET 4 程序集的硬编码列表。 如果 ASP.NET 4 未这样做,则在 ASP.NET 内部代码的第一行尝试在部分信任应用程序域中运行时,Web 应用程序会立即失败。
在 .NET Framework 4 中,条件 APTCA 是一个新 CAS 概念,该概念尚未在 .NET Framework 的其他部分中实现。 因此,.NET Framework 的将来版本可能会包含更多的条件 APTCA 程序集。 此外,随着您逐渐了解条件 APTCA 并将其用于自己的完全信任程序集,条件 APTCA 程序集组也会不断增大。 因为 ASP.NET 4 不可能事先知道所有可能的条件 APTCA 程序集,所以 ASP.NET 4 包含了一个可向其中添加条件 APTCA 程序集的配置节。
现有 securityPolicy 节有一个名为 partialTrustVisibleAssemblies 的子配置节。 这是一个支持添加、移除和清除操作的标准集合,您可以在其中指定应视为 APTCA 的一个或多个程序集标识(如果它们同时标记为条件 APTCA)。 下面的示例演示 partialTrustVisibleAssemblies 节。
<system.web>
<securityPolicy>
<partialTrustVisibleAssemblies>
<add assemblyName="MyCustomAssembly"
publicKey="a 320 hex character representation
of the public key blob used with a
signed assembly"
/>
</partialTrustVisibleAssemblies>
</securityPolicy>
</system.web>
partialTrustVisibleAssemblies 节中的每个条目通过程序集名称来标识程序集。 每个条目还由一个 320 个字符的字符串(例如 0x03FA4D...)标识,该字符串是签名密钥(用于具有条件 APTCA 特性的程序集)公开的半部分的十六进制字符表示形式。 您不必指定版本特性。 CLR 只需要程序集名称和公钥标记。
启用条件 APTCA 程序集时的一个重要性能因素是还应启用条件 APTCA 程序集的传递闭包。 例如,如果条件 ATPCA 程序集 A 依赖于 APTCA 程序集 B,而 APTCA 程序集 B 又依赖于条件 ATPCA 程序集 C,则为 A 启用条件 ATPCA 时,还应为 C 启用条件 APTCA。 否则,应用程序的性能可能会受到影响。 例如,如果未启用完全条件 ATPCA 闭包,则会禁用代码共享和 NGen 映像。
条件 APTCA 对非 Web 部分信任应用程序有何影响
在 ASP.NET 4 之前的 ASP.NET 版本中,某些类型和命名空间未通过 AspNetHostingPermission 特性进行标记。 这会允许从非 ASP.NET 部分信任环境(如 ClickOnce 应用程序)中调用这些类型。 可以通过此方式调用的类型和命名空间如下:
System.Web.ClientServices 命名空间中的类型。
System.Web.ClientServices.Providers 命名空间中的类型。
HttpUtility 类型。
System.Web.ClientServices 类型不能在 .NET Framework 4 部分信任环境(如 ClickOnce)中使用。 因为包含程序集 (System.Web.Extensions.dll) 是针对条件 APTCA 标记的 ASP.NET 4 程序集,并且因为 ClickOnce 不允许将 APTCA 用于任何条件 APTCA 程序集,所以任何客户端服务类型都不能从部分信任 ClickOnce 应用程序中进行调用。
出现此行为的原因有多种。 首先,.NET Framework 4 已拆分为一个客户端和一个扩展 SKU,并假设许多 ClickOnce 应用程序将面向客户端 SKU。 将 ASP.NET 客户端服务类型重构到客户端 SKU 需要进行大量工作。
其次,确定如何在维持所需条件 APTCA 边界的同时重构客户端类型是十分复杂的。 因此,在 .NET Framework 4 中,客户端服务类型仅对非 ASP.NET 完全信任环境可用,包括使用扩展 .NET Framework 4 SKU 配置为以完全信任方式运行的 ClickOnce 应用程序。
对于 HttpUtility 类型,条件 APTCA 的影响具体决于所使用的方法,如以下方案中所示:
部分信任代码调用 WebUtility 类的 HtmlEncode 或 HtmlDecode 方法。 WebUtility 类型包含 ASP.NET HTML 编码和解码实现,但这些实现已重构并移动到 System.Net 命名空间中,而该命名空间包含在 System.dll 中。 因为 System.dll 可在所有部分信任主机环境中使用,所以使用 WebUtility 类型的方法访问非 ASP.NET 部分信任应用程序是没问题的。
部分信任代码调用 WebUtility 类的任何其他方法。 在此情况下,将出现前面针对客户端服务所述的相同问题。 也就是说,WebUtility 仅对 .NET Framework 4 中的非 ASP.NET 完全信任调用方可用。
ASP.NET 4 中的安全透明度
通过安全透明度可以向 CLR 指示代码块是否将执行安全敏感性操作。 透明代码绝不能断言权限、满足链接要求、包含无法验证的代码、调入本机代码或调用安全关键型代码。 无论透明代码是完全信任(例如在 GAC 中)还是部分信任,情况都是如此。
安全透明度是针对 .NET Framework 功能(如 ASP.NET)的一项强大功能。 该功能使 ASP.NET 可以向 CLR 指示部分 ASP.NET 代码绝不会断言权限,并且该代码绝不会实现或执行安全敏感操作(如进入本机代码的 PInvoke 调用)。 这样,.NET Framework 代码便可显著降低大量公共和内部 API 的安全风险,即使 .NET Framework 代码位于完全信任的 GAC 中也是如此。
安全透明度可以应用于整个程序集,也可以仅应用于程序集中的代码子集。 虽然理想情况下是针对安全透明度标记整个程序集,但是 .NET Framework 中的某些代码具有执行安全敏感任务的合理要求。 包含 100% 安全透明代码的程序集将使用程序集级别 SecurityTransparentAttribute 特性进行标记。
同时包含透明和非透明代码的程序集没有程序集级别的透明度特性。 程序集中的各个类可以改为使用 SecuritySafeCriticalAttributel 特性或 SecurityCriticalAttribute 特性进行标记。
非特性化类的行为十分复杂。 但是,简而言之,ASP.NET 4 程序集中采用新透明度模型的非特性化类型会被视为安全透明。 ASP.NET 4 程序集中未特性化且未采用新透明度模型的类型会被视为安全可靠关键的。
做法和安全规则集中的安全透明度
因为有如此之多的 ASP.NET 4 基本代码位于 System.Web.dll 中,所以将所有 ASP.NET 4 代码都转换为新透明度模型是不切实际的。 可以改为将 ASP.NET 4 代码划分为以下类别:
不采用新透明度模型的代码,包括以下程序集中的代码:
System.Web.dll
System.Web.ApplicationServices.dll
System.Web.Mobile.dll。 此程序集中的类型在 ASP.NET 4 中已标记为过时。 即使该程序集仍然存在,预计您也将随着时间的推移而停止使用此程序集中的类型。
使用新透明度模型的代码,包括以下程序集中的代码:
System.Web.Extensions.dll
System.Web.DynamicData.dll(100% 安全透明)
System.Web.RegularExpressions.dll(100% 安全透明)
System.ComponentModel.DataAnnotations.dll
System.Web.DataVisualization.dll
只包含元数据及其类型已移动到其他 ASP.NET 程序集中的程序集,包括以下程序集:
System.Web.Abstractions.dll。 早期版本 ASP.NET 中此程序集中的类型已移动到 System.Web.dll 中。 因此,Sytem.Web.Abstractions.dll 在 ASP.NET 4 中是仅包含元数据的程序集。
System.Web.Routing.dll。 早期版本 ASP.NET 中此程序集中的类型已移动到 System.Web.dll 中。 因此,Sytem.Web.Abstractions.dll 在 ASP.NET 4 中是仅包含元数据的程序集。
在 .NET Framework 4 中,CLR 引入了一个称为安全规则集的新概念。 有两个级别的 SecurityRuleSet 配置,即级别一和级别二。 所有类型的 SecurityRuleSet 配置均使用 SecurityRulesAttribute 程序集级别特性指定。 采用新透明度模型的 ASP.NET 4 程序集使用以下程序集级别特性进行标记:
System.Security.SecurityRules(RuleSet=System.Security.SecurityRuleSet.Level2)
使用 .NET Framework 2.0 中的透明度模型(该模型对于 ASP.NET 实际上表示不透明,因为 ASP.NET 4 之前的 ASP.NET 从不使用透明度概念)的 ASP.NET 4 程序集使用以下程序集级别特性进行标记:
System.Security.SecurityRules(RuleSet=System.Security.SecurityRuleSet.Level1)
对于采用新透明度模型的 ASP.NET 程序集(以及程序集中的公共类型),多数代码都被视为安全透明。 这些程序集中的少量代码执行安全敏感操作,这些代码会标记为安全关键或关键代码。
对于不采用新透明度模型的 ASP.NET 程序集(搁置过时或类型重定向的程序集),所有公共 API 都可以从部分信任用户代码调用并可以在内部执行安全敏感操作。 同时考虑到对部分信任调用方的公开访问和可能进行安全敏感操作,这意味着较旧的 ASP.NET 4 代码需要加强审查力度。 不过,因为多数新 ASP.NET 功能都在较新程序集(如 System.Web.Extensions.dll 和 System.Web.DynamicData.dll 中)或在单独的版本(如 ASP.NET MVC)中实现,所以多数新 ASP.NET 代码是安全透明的,因此默认情况下比旧代码更安全。
默认情况下,只要宿主环境采用 APTCA 特性,CLR 就会将标记为 SecurityRuleSet.Level1 的所有 ASP.NET 4 程序集的公共 API 视为是安全关键的(即,相当于通过 SecuritySafeCriticalAttribute 特性进行标记)。 如果不采用 APTCA,则 CLR 会触发针对完全信任的链接要求,当堆栈上存在任何部分信任用户代码时,该要求会失败。 换句话说,如果对标记为 SecurityRuleSet.Level1 的 ASP.NET 程序集采用 APTCA,则当部分信任代码尝试调用未通过 APTCA 特性进行标记的完全信任程序集时,您会看到与以前版本 .NET Framework 中相同的行为。
默认情况下,只要宿主环境采用 APTCA 特性,CLR 就会将标记为 SecurityRuleSet.Level2 的所有 ASP.NET 4 程序集的公共 API 视为是安全透明的(即,相当于使用 SecurityTransparentAttribute 进行特性化)。 否则,将定义以下行为:
如果不采用 APTCA 并且标记为 Level2 的程序集不是 100% 安全透明的,则 CLR 会将公共外围应用视为是安全关键的。 因此,任何尝试使用公共外围应用的部分信任调用方都可能会失败,并出现 MethodAccessException、TypeAccessException 或 FieldAccessException 异常。
如果不采用 APTCA 并且标记为 Level2 的程序集是 100% 安全透明的,则部分信任调用方能够成功调用该程序集中的任何公共 API。 实际上,这意味着当 100% 安全透明程序集中的代码最终调入不是 100% 安全透明的级别 1 ASP.NET 程序集或级别 2 ASP.NET 程序集时,随后会在调用路径中出现 SecurityException 异常。
透明度和 ASP.NET 编译
ASP.NET 4 同时采用新 CAS 模型和新安全透明度模型,也会影响 ASP.NET 编译系统创建的输出。 输出包括页程序集、预编译的程序集和 App_Code 目录的编译结果等。 编译系统根据 trust 元素的 LegacyCasModel 特性的设置改变其行为。。
下表介绍如何在旧 CAS 模型和较新的 CAS 模型中标记动态编译的对象。
legacyCasModel 特性设置 |
网站信任级别 |
应用于已编译程序集的特性 |
---|---|---|
False(新 CAS 模型) |
完全信任 |
SecurityRules(SecurityRuleSet.Level2) |
高或较低级别信任 |
SecurityRules(SecurityRuleSet.Level2) |
|
SecurityRules(SecurityRuleSet.Level2) |
||
True(旧 CAS 模型) |
完全信任 |
SecurityRules(SecurityRuleSet.Level1) |
高或较低级别信任 |
SecurityRules(SecurityRuleSet.Level1) |
ASP.NET 4 编译系统根据 trust 元素的 LegacyCasModel 特性的设置改变其行为,因此,在不同的部分信任 ASP.NET 4 应用程序共享已编译代码的方式上,可能存在限制。 通常,应用程序行为不会有任何变化。 不过,在某些情况下,从 LegacyCasModel 特性设置为 false 的部分信任应用程序(也就是使用新 CAS 模型)创建的已编译项目不会像用于其他应用程序时那样正常工作。 因此,在某些方案(例如,部署在 GAC 中、经过 ATPCA 特性化和签名的已编译 .ascx 控件的共享库)中,如果使用 Level2 对该库进行标记,可能必须将安全关键和关键的特性应用于某些代码。