.NET Framework 4 中的安全性更改

.NET Framework 4 版中对安全性进行了两大更改。 已消除计算机范围的安全策略,但权限系统仍然起作用,并且安全透明度已成为默认强制机制。 (有关更多信息,请参见安全透明的代码,级别 2。)此外,已弃用一些可能造成安全漏洞的权限操作。

重要说明重要事项

未取消代码访问安全性 (CAS) 设置,已从 CAS 中取消安全策略,但证据和权限仍起作用。已取消某些权限,并且透明度已简化了安全性的强制实施。有关这些更改的简要概述,请参见代码访问安全性更改的摘要

您应注意以下要点:

  • 透明度可将作为应用程序的一部分运行的代码与作为基础结构的一部分运行的代码分离。 .NET Framework 2.0 版中引入了透明度,并对透明度进行了增强,使其成为了代码访问安全性强制机制。 与安全策略不同,2 级透明度规则是在运行时而非程序集加载时强制执行的。 这些规则始终是有效的,甚至对于在默认情况下作为完全受信任的程序集运行的程序集也是这样。 但是,2 级透明度不会影响未进行批注的完全受信任代码(如桌面应用程序)。 用 SecurityTransparentAttribute 标记的并调用了用 SecurityCriticalAttribute 标记的方法的程序集(包括桌面程序集)会收到 MethodAccessException。 通过应用 SecurityRulesAttribute 并将 SecurityRulesAttribute.RuleSet 属性设置为 Level1,可以更改此行为;但是,应该仅在实现向后兼容时执行此操作。必须将桌面应用程序显式标记为安全透明,以便对其应用透明度限制。

  • 调用安全策略 API 的代码在运行时会收到 NotSupportedException 和编译器警告。 可以使用 <NetFx40_LegacySecurityPolicy> 配置元素重新启用策略。 启用策略后,安全透明度仍然有效。 安全策略是在程序集加载时应用的,并且对透明度(它是在运行时强制执行的)没有影响。

  • 已过时的请求权限(RequestMinimumRequestOptionalRequestRefuse)接收编译器警告并且在 .NET Framework 4 中不起作用,但它们不会导致引发异常。 Deny 请求会导致在运行时引发 NotSupportedException

  • 虽然 LinkDemand 安全操作未过时,但不应将其用于验证权限。 相反,应为需要完全信任的类型和方法使用 SecurityCriticalAttribute,或为需要各个权限的类型和方法使用 Demand 方法。

  • 如果应用程序是使用 Visual Studio 2010 生成的,您可以通过在 Visual Studio 项目设置中指定一个 .NET Framework 4 之前的目标 .NET Framework 版本,在不进行上述更改的情况下运行该应用程序。 但您将无法使用新的 .NET Framework 4 类型和成员。 也可以通过使用应用程序配置文件的启动设置架构中的 <supportedRuntime> 元素来指定早期版本的 .NET Framework。

以下各节讨论了上述更改以及 .NET Framework 4 中的其他更改: 

  • 安全策略简化

  • 2 级安全透明度

  • 过时权限请求

  • 条件 APTCA

  • 证据对象

  • 证据集合

安全策略简化

从 .NET Framework 4 开始,公共语言运行时 (CLR) 不再为计算机提供安全策略。 一直以来,.NET Framework 都会提供代码访问安全 (CAS) 策略作为用于严格控制和配置托管代码的功能的机制。 虽然 CAS 策略的功能强大,但它可能很复杂且具有一些限制。 此外,由于 CAS 策略不适用于本机应用程序,因此其安全保证是有限的。 系统管理员应在 Windows 7 和 Windows Server 2008 R2 上使用操作系统级别的解决方案(如 Windows Software Restriction Policies(Windows 软件限制策略)(SRP) 或 AppLocker 来替代 CAS 策略。 SRP 和 AppLocker 策略提供适用于托管代码和本机代码的简单信任机制。 作为安全策略解决方案,SRP 和 AppLocker 不仅比 CAS 更加简单,而且能够提供比 CAS 更好的安全保证。

在 .NET Framework 4 中,默认情况下已关闭计算机范围的安全策略。 此时,未承载的应用程序(即,通过 Windows 资源管理器或命令提示符执行的应用程序)将作为完全信任应用程序运行。 这包括驻留在本地网络共享中的所有应用程序。 承载应用程序或沙盒应用程序仍在其宿主(如通过 Internet Explorer、ClickOnce 或 ASP.NET)决定的信任策略下运行。 沙盒中运行的应用程序或控件被视为是部分受信任的。

为了简化安全策略,已将透明度模型应用于 .NET Framework。 在宿主或沙盒中运行的、具有由沙盒授予的有限权限集的应用程序和控件被视为是透明的。 透明度意味着,您在运行部分受信任的应用程序时无需考虑检查 CAS 策略。 透明应用程序仅使用其授予集来运行。 作为一个程序员,您只应注意以下事项:应用程序以其沙盒的授予集为目标并且应用程序不调用需要完全信任的代码(安全关键代码)。

重要说明重要事项

完成这些安全策略更改后,如果(通过其他类型和成员)显式或隐式调用过时的 CAS 策略类型和成员,则可能遇到编译警告和运行时异常。有关过时类型和成员及其替换项的列表,请参见代码访问安全策略兼容性和迁移

通过使用运行时设置架构中的 <NetFx40_LegacySecurityPolicy> 配置元素选择使用旧版 CAS 策略行为,可以避免这些警告和错误。但是,指定使用旧版安全策略并不包括该版本的任何自定义 CAS 策略,除非将该版本迁移到 .NET Framework 4。

通过将 Visual Studio 项目的目标 .NET Framework 版本设置为早于 .NET Framework 4 的版本,还可以启用旧 CAS 策略。这将启用旧 CAS 策略并包括您为该版本指定的任何自定义 CAS 策略。但您将无法使用新的 .NET Framework 4 类型和成员。也可以通过使用启动设置架构中的 <supportedRuntime> 元素来指定早期版本的 .NET Framework。

返回页首

2 级安全透明度

虽然 .NET Framework 2.0 版中引入了安全透明度,但此安全透明度是非常有限的,并且主要用于提高代码验证效率。 在 .NET Framework 4 中,透明度是一类强制机制,它可将作为应用程序的一部分运行的代码与作为基础结构的一部分运行的代码分离。 透明度在可以执行特权操作(例如调用方本机代码)的代码(关键代码)与不可执行特权操作的代码(透明代码)之间设置了一个屏障。 透明代码可以在其运行于的权限集的边界内执行命令,但无法执行、调用、派生自或包含关键代码。

透明度强制的主要目的是为了提供用于基于特权隔离不同的代码组的简单而有效的机制。 在沙盒模型中,这些特权组要么是完全受信任的(即不受限制),要么是部分受信任的(即限于授予给沙盒的权限集)。

桌面应用程序作为完全受信任的应用程序运行;它们不受透明度模型的影响。 有关安全透明度更改的更多信息,请参见安全透明的代码,级别 2

返回页首

过时权限请求

已移除对于强制执行 DenyRequestMinimumRequestOptionalRequestRefuse 权限请求的运行时支持。 一般来说,这些请求未被正确地理解,而且在未正确使用这些请求的情况时,可能会导致出现安全漏洞:

  • Assert 操作可轻松重写 Deny 操作。 如果某个权限包含在一个程序集的授予集中,则此程序集中的代码可以为该权限执行 Assert 操作。 Assert 已阻止 Deny 在堆栈上出现,从而使其无效。

  • 未能在应用程序范围外有效使用 RequestMinimum。 如果 RequestMinimum 在一个可执行 (.exe) 文件中出现并且授予集不符合要求,则该文件的最终用户收到一个未经处理的 FileLoadException 异常,此异常未包含有关如何解决问题的任何信息。 未能为库(.dll 文件)使用单个最小请求集,因为程序集中不同的类型和成员通常会具有不同的权限要求。

  • RequestOptional 易于混淆,并且通常会因使用不当而导致意外结果。 开发人员很容易忽略列表中的权限,而不会意识到这样做会导致隐式拒绝忽略的权限。

  • RequestRefuse 不提供有效的最小特权模型,因为它要求您显式标识不需要的权限,而不是标识所需的权限。 另外,新权限在变为可用后将不会包含在列表中。 此外,拒绝对于所有权限都没有任何意义。 例如,可以拒绝 IsolatedStoragePermissionUserQuota 属性的值。

    最后,如果仅指定不需要的权限,则在您未能标识所有可能有害的权限的情况下,可能会导致安全漏洞。

  • 利用 RequestOptionalRequestRefuse,开发人员可以通过在域中创建多个权限集来中断同源域。

.NET Framework 4 移除针对这些枚举值的运行时强制。 包含使用这些 SecurityAction 值的特性的程序集将继续加载;但是,CLR 将不会拒绝加载引用程序集或根据权限集修改其授予集。

返回页首

条件 APTCA

通过有条件地使用 AllowPartiallyTrustedCallersAttribute (APTCA) 特性,主机可以标识要向主机上下文中加载的部分信任调用方公开的程序集。 候选程序集必须已针对部分信任进行设计;也就是说,候选程序集必须是 APTCA(透明度模型中的安全可靠关键),或者必须是完全透明的。 通过 AllowPartiallyTrustedCallersAttribute 的新构造函数,主机可在构造函数调用中使用 PartialTrustVisibilityLevel 枚举,从而指定 APTCA 程序集的可见性级别。

返回页首

证据对象

在 .NET Framework 4 之前,几乎任何对象都可用作证据对象(如果承载代码想要将其作为证据应用)。 例如,某些 .NET Framework 代码将 System.Uri 对象识别为证据。 运行时将证据对象视为 System.Object 引用,而且未对它们应用任何类型的安全。

这就造成一个问题,因为 .NET Framework 对可用作证据对象的类型强加了隐式限制。 特别是,任何用作证据的对象都必须是可序列化的,且不能为 null。 如果不满足这些要求,无论何时执行需要这些假设之一的操作,CLR 都将引发异常。

为了在可用作证据的对象的类型上启用约束并提供为所有证据对象添加新功能和要求的能力,.NET Framework 4 引入了新的基类 System.Security.Policy.EvidenceBase,所有证据对象都必须从该基类派生。 EvidenceBase 类确保在实例化时证据对象是可序列化的。 此外,以后可以通过将新的默认实现添加到基类来创建新的证据要求。

向后兼容性

CLR 用作证据对象的所有类型已在 .NET Framework 4 中得到更新,以派生自 EvidenceBase。 但是,无法知道和更新由第三方应用程序使用的自定义证据类型。因此,无法将这些证据类型与预期证据派生自 EvidenceBase 的新成员结合使用。

返回页首

证据集合

在 .NET Framework 4 之前,CLR 会在一个程序集加载时生成适用于该程序集的完整证据对象集。 这些对象存储在一个列表中,使用者稍后将循环访问此列表以查找特定对象。 因此,所有证据都已变为可用,不管是否已使用它们。 此行为对于大多数证据对象不是问题;但是,对于如 System.Security.Policy.Publisher(它要求 Authenticode 验证)这样的证据对象,此行为不起作用。

为了改进此行为,已在 .NET Framework 4 中重新设计了与证据集合的交互。 证据集合现在的行为方式类似于字典而不是列表。 现在,使用者不用循环访问证据集合以查看所需的证据对象是否存在,而只需请求特定类型的证据,证据集合就会返回该证据(如果找到了该证据)。 例如,如果 StrongName 对象存在,则调用 StrongName name = evidence.GetHostEvidence<StrongName>(); 将返回该对象;否则返回 null。

此字典模型会将证据对象的生成推迟到相关方请求这些对象时执行。 在 Publisher 证据示例中,验证程序集的 Authenticode 签名的性能开销将会推迟到需要相关信息时才会发生。 对于完全信任应用程序,最常见的情况是不需要 Publisher 证据,此时可完全避免验证过程。

返回页首

请参见

概念

安全透明的代码

安全透明的代码,级别 2

代码访问安全策略兼容性和迁移