内侧 out 的 CLR

探究 .NET Framework 4 安全模式

Andrew Dai

.NET Framework 4 对 .NET 安全模式进行了大量更新,使其更加便于托管、更加安全并且可向部分信任的代码提供服务。我们 overhauled 复杂的代码访问安全性 (CAS) 策略系统,这是功能强大,但难以使用和甚至更难获得权限。我们也得到改进安全透明模型时使 Silverlight 改进的很多 (其中我谈最后十月:msdn.microsoft.com/magazine/cc765416.aspx) 到桌面的框架的安全性强制中。最后,我们引入一些让主机和库的开发人员更灵活地通过其中公开其服务的新功能。这些更改与.net Framework 4 boasts 可以很容易为主机和库沙盒代码和库来安全地公开服务到一个更简单、 改进的安全模型。

在.net Framework 安全中背景

之前深入了解任何特定的功能,它有助于有一点背景上安全,.NET Framework Framework中的工作原理。由它具有的权限限制部分受信任的代码和不同的 api 将需要不同的权限成功进行调用。CAS 的目标是确保不受信任的代码具有适当权限运行,并且 can’t 执行未经授权其权限之外的任何操作。

我们可以认为.net 安全模型作为三个部分组成。在每个区域中所做具体改进,并根据这些三个基本部分,本文的其余部分组织:

  • 策略 — 安全策略确定哪些权限授予特定不受信任的程序集或应用程序。托管的代码中有与它,可以描述代码加载位置从,等发布者的关联的证据对象。证据可用于确定适当的权限 ; 结果名为权限授予集。.NET Framework Framework具有控制这传统上为计算机范围机制使用 CAS 策略。如前所述,CAS 策略已被 overhauled 而通过它们自己的安全策略和与本机代码的 unhosted 的代码奇偶校验给予主机更大的灵活性。
  • 砂盒 — 沙盒处理是实际的限制程序集的过程或应用程序以给定的权限授予集。以沙盒首选的方法是创建包含特定的库程序集 (这些都授予完全信任) 设置的已加载的程序集和免除列表的权限授予一个沙盒处理应用程序域。与 CAS 策略的 obsoletion,部分信任代码始终获取沙盒这种方式在.net Framework 4。
  • 强制 — 强制指的是保持不受信任的代码限于其沙盒机制。强制实施 api 的正确使用可防止简单地在不同的、 受信任的更多的程序集调用的 API 和行使更大权限这种方式从一个不受信任的程序集。它还允许主机和库的开发人员公开受控制的、 有限的访问,以提升的行为,并提供有意义的服务,部分受信任的代码。级别 2 安全透明模型使得更易于安全地执行此操作。

.NET 安全模型始终被的特定主机和库的开发 (人员经常手动在手头转) 的重要性。.NET 安全模型的示例包括 ASP.NET 和 SQL CLR 哪两个主持受控制的环境和受限制的上下文内的托管的代码。当这些主机要加载部分受信任的程序集时,它将创建与适当的权限授予集沙盒应用程序域。程序集然后被加载到此沙盒域中。主机还提供了库完全受信任但可从托管代码调用的 api。在库也是加载到沙盒域,但显式放置在前面提到的免除列表上。它们依赖于.NET Framework Framework已经强制机制,以确保严格控制访问其提升的能力。

对于大多数托管应用程序开发人员这是所有魔术的框架级别上发生 — 甚至是开发人员编写的代码将在沙箱中运行 don’t 需要了解的安全模型是如何工作的所有详细信息。框架可确保沙盒代码仅限于使用 api 和主机提供的能力。.NET 安全模型和 CAS 有多长时间被企业管理员和主机和库的开发人员的领域 ; 为它们,我们做事情变得比过去更容易。

策略

.NET Framework Framework为计算机和企业管理员提供一种方式进行微调,运行库视为受信任或不受信任的开始后,您已提供了 CAS 策略。尽管 CAS 策略已非常强大而且非常精细的控件允许,程序极难获取右和可能会影响多个帮助。计算机管理员可以锁定某些应用程序超出了所需的权限 (在下一次的主要部分沙盒描述) 和许多人想知道为什么他们的应用程序突然停止工作一旦他们决定在将它们放在网络共享上。此外,CAS 策略设置 didn’t 向前移动从一个版本的运行库为另一,以便手动恢复.net Framework 2.0 不得不精心设计的自定义 CAS 策略某人在.net Framework 1.1 中设置的。

安全策略可能被拆分成两种方案:计算机或企业的托管代码和安全策略的安全策略。计算机策略有关公共语言运行库安全小组决定为本机代码显然不是受限于其限制,运行库将被错误的位置,以控制它。虽然有意义的能够确定其宿主的代码可以执行的操作主机,unhosted 的 exe,只需单击它或从命令行运行应行为与与其本机对应项 (特别是因为它们看起来与运行它们的用户相同)。

在该操作系统级别这样的策略将应用于本机和同等托管代码的位置是正确的位置为全局安全策略。因此,我们鼓励计算机管理员,默认情况下查看解决方案 (如 Windows 软件限制策略和禁用计算机范围 CAS 策略解析。在其他方案的托管代码的安全策略在托管的代码世界是仍然非常有效。主机安全策略现在是更方便地控制,因为它不再能用任意计算机的策略将冲突。

这意味着对于您

一个,所有 unhosted 默认情况下以完全信任的托管的代码运行。如果从您的硬盘或网络共享中运行一个.exe 您的应用程序必须运行相同的位置从一个本机应用程序将具有的所有功能。宿主的代码但是,是仍服从于安全决策的 (代码可以通过 Internet 到达方法的所有承载方案的笔记 — ClickOnce 应用程序的示例 — — 这并不意味着通过 Internet 运行的代码是完全受信任以便) 主机。

对于许多应用这些更改主要是在背景中并没有察觉到的影响。受更改的那些可能会遇到两个问题。第一种方法是某些 CAS 策略相关 api 被否决,许多不必与程序集加载 (这样阅读上,如果执行此操作根本)。第二个,和影响少的人 (主要主机),将为异类应用程序域 (它沙盒部分中所述) aren’t 默认情况下可用的事实。

但我不执行任何这样的 !如何只是使其工作?

也许您运行到错误或 obsoletion 邮件看起来类似于下面这样的:

此方法隐式 [显式/地] 使用已被 obsoleted 由.NET Framework Framework的 CAS 策略。若要启用,兼容性原因的 CAS 策略,请使用 NetFx40_LegacySecurityPolicy 配置开关。请有关详细信息,参阅 [MSDN 文档链接]。

出于兼容性原因,我们提供允许进程启用 CAS 策略解析在其上的一配置开关。您可能会通过您的项目已经 app.config 文件中放置以下启用 CAS 策略:

<configuration>
   <runtime>
      <!-- enables legacy CAS policy for this process -->
      <NetFx40_LegacySecurityPolicy enabled="true" />
   </runtime>
</configuration>

以下部分介绍从何处开始寻找迁移,如果从您自己的代码引发异常。如果它 isn’t 然后配置开关是途径和下一节 shouldn’t 应用直接给您。

受影响的 api

可以将受影响的 api 分为两组:显式使用 CAS 策略和那些隐式地使用它的那些。显式的用法是明显 — — 它们倾向于驻留在 System.Security.Policy.SecurityManager 类并看起来类似于 SecurityManager.ResolvePolicy。这些 api 直接调用或修改计算机已经的 CAS 策略设置,它们具有所有被否决。

隐式的用法是不太明显 — — 这些往往是程序集加载或采取证据的应用程序域创建。上此证据解析 CAS 策略和结果的权限授予集与加载程序集时。默认情况下是关闭的 CAS 策略,因为它 doesn’t 意义来尝试解决此证据上。Assembly.Load (AssemblyName assemblyRef、 证据 assemblySecurity) 是 API 的这样的示例。

有几个原因调用此类 API 的原因:

  1. 砂盒 — Perhaps 您知道是从 Internet 区域证据与调用该 Assembly.Load 重载将产生的与 Internet 正在加载的程序集命名权限集 (除非,就是管理员更改了该证据映射为此特定计算机或用户!)。
  2. 对重载的其他参数 — — 也许只是想获取到此重载只能存在于某个特定参数。在这种情况下您可能只需传递空值或为证据参数 Assembly.GetExecutingAssembly ().Evidence。

如果试图沙盒,沙盒部分描述如何创建命名权限集 Internet 仅限于一个沙盒应用程序域您的程序集可以然后是加载到该域,并有权限在预期的保证 (也就是不取决于管理员的愿望)。

在第二个方案中我们添加到每个这些 api 公开所有必需的参数,但 don’t 公开证据参数的重载。迁移是剪切的一个简单掉到您的呼叫证据参数。(注意已过时的 api 传递空证据仍然适用一样好视为它 doesn’t 中 CAS 策略评估结果)。

其他需要注意的一件事情是,如果您执行的操作程序集加载从远程位置 (也就是 Assembly.LoadFrom(“http://...”)),最初收到一个 FileLoadException 除非设置了以下配置开关。这样做是因为此调用将 ’ve 沙盒在过去程序集。与不见了 CAS 策略,它是完全受信任!

<configuration>
   <runtime>
      <!-- WARNING: will load assemblies from remote locations as fully
         trusted! -->
      <loadFromRemoteSources enabled="true" />
   </runtime>
</configuration>

若要为整个进程关闭此开关的情况下执行此的另一种方法是使用与开关集的作用如同 LoadFrom 新 Assembly.UnsafeLoadFrom API。如果要启用远程装载中的某些位置或 don’t 拥有主应用程序,这是很有用。

出图片的计算机范围 CAS 策略,与所有的检查程序集证据和适当的权限集有关的决策是从左到托管代码的主机向上。无干扰其安全决策 (除了从任何 OS 安全策略中) 它顶部的复杂系统,主机是可用来分配它自己的权限。现在它 ’s 时间若要给部分信任程序集的那些权限。

沙盒

通过主机已经的安全策略我们可以确定正确的权限授予集为部分信任程序集赋予。现在,我们需要一种简单而有效的方法,该集加载到仅限于该特定的授权集的环境。尤其使用简单沙盒 CreateDomain 重载沙盒处理就是用于完成此操作。

在过去的沙盒

与旧的 CAS 策略模型时可能会创建一个域中的每个程序集拥有其自己的访问权限的位置下的异类应用程序域设置。与 Internet 区域证据的程序集加载可能会导致在被加载到完全信任程序集进行加载相同的域的不同部分信任级别的两个或多个程序集。此外,应用程序域可以有它自己为其赋予它自己的权限集的证据。

有与此模型的几个问题:

  • 权限集授予对程序集是依赖于 CAS 策略,如多个策略级别交叉来计算最终的权限集。因此,有可能得到比预期更少的权限。
  • 类似于前一点,证据评估程序集上的完成的方法是: 跨计算机、 用户和甚至版本的运行库 (CAS 策略设置 didn’t 向前移动与新版本的运行库) 可能不同的 CAS 策略。因此,它 wasn’t 总是很明显获取程序集哪些权限授予集。
  • 部分信任程序集不通常强化,使 “ 中间信任 ” 的程序集为 “ 最低信任 ” 的程序集易受攻击的安全检查。  程序集是自由地能够调用彼此,以便让它们使用不同的能力的许多成为从安全角度有问题。有人可以确定每种组合来自不同信任级别上的程序集调用的是安全吗?它是绝对安全地缓存信息从中间信任层吗?

因这些问题我们引入了同类的应用程序域,其中包含只有两个权限授予集 (部分信任和完全信任),可以创建和有关原因非常简单的概念。同类域以及如何创建这些,在此部分中稍后介绍。

有关砂盒流行的另一种机制 PermitOnly 的使用,是堆栈的拒绝步行修饰符,该列表的特定允许的权限 (和执行任何操作多个),并分别禁止特定的权限。似乎有用说,“ 我只需调用方拥有权限 x 和 y 若要能够调用此 API ” 或 “ 的 API 作为要向所有我调用方拒绝权限 ”但是,这些修饰符 做实际上不会更改特定的程序集的权限授予集 ,这意味着他们可以将断言走因为 他们所做的截距要求 。在操作中的此示例显示在 的 图 1 中。

图 1 A 调用堆栈表示在沙盒处理与一个尝试拒绝

没有红色 Assert,需求命中次数拒绝,并终止堆栈审核。激活红色 Assert 时但是,拒绝永远不会命中,如 Untrusted 已断言请求走。(备注:向下增长调用堆栈。api 不代表在框架中的实际 api)。出于此原因拒绝否决中.NET Framework Framework 4 中,因为使用它始终是安全漏洞 (PermitOnly 是仍然周围,因为可以合法地使用几个角情况下,但通常反对这样做)。请注意它可以被重新激活使用 NetFx40_LegacySecurityPolicy 开关,上面策略一节中提到。

今日沙盒处理

对于.NET Framework Framework隔离,我们使用的单位是应用程序域。每个部分信任应用程序域都有除外为专门在完全信任免除列表中列出,或从全局程序集缓存加载的所有程序集加载到它获得一个单独的权限授予集。创建此域是非常简单 —.NET Framework Framework提供了一个简单的沙盒 API 中的所有内容采用您的需要创建域:

AppDomain.CreateDomain( string friendlyName,
 
                        Evidence securityInfo,
                        
                        AppDomainSetup info,
                        
                        PermissionSet grantSet,
                        
                        params StrongName[] fullTrustAssemblies);

该参数在哪里:

  • friendlyName — 应用程序域的友好名称。
  • securityInfo — 证据与应用程序域相关联。这 isn’t 用于 CAS 策略的分辨率,显然,但用于存储诸如出版商信息。
  • 信息 — 应用程序域初始化信息。这必须包括,最少,表示部分信任程序集所在的位置存储一个 ApplicationBase。
  • grantSet — 将权限授予集的所有已加载的程序集在该域上完全信任列表或全局程序集缓存中除外。
  • fullTrustAssemblies — StrongNames 的被授予完全信任 (从部分信任的免除) 的程序集的列表。

一旦域创建您可以调用上一个 MarshalByRefObject 的 AppDomain.CreateInstanceAndUnwrap 中您部分信任的程序集,然后调用转换到 kick 关闭,其入口点方法, 的 图 2 所示。

图 2 的 与内部运行的部分信任代码的沙盒

PermissionSet permset = new PermissionSet(PermissionState.None);
ps.AddPermission(new SecurityPermission(
   SecurityPermissionFlag.Execution));
AppDomainSetup ptInfo = new AppDomainSetup();
ptInfo.ApplicationBase = ptAssemblyStore;
 
AppDomain sandboxedDomain = AppDomain.CreateDomain(
   "Sandbox",
   AppDomain.CurrentDomain.Evidence,
   ptInfo,
   permset);
 
// assume HarnessType is in the GAC and a MarshalByRef object

HarnessType ht = sandboxedDomain.CreateInstanceAndUnwrap(
   typeof(HarnessType).Assembly.FullName,
   typeof(HarnessType).FullName)
   as HarnessType;
 
ht.LoadPTEntryPoint();

大功告成!使用几行代码,我们现在具有在它运行的部分信任代码与一个沙盒。

此 CreateDomain API 实际上是在.net Framework 2.0,添加,因此 ’s 不新。但是,它 ’s 值得一提如现在 ’s 沙盒代码唯一真正受支持的方法。正如您所看到的权限集直接传递,因此没有证据具有要进行求值在程序集加载到此域中 ; 您确切知道哪些每个已加载的程序集将要获得。此外,使用真实隔离边界包含已在进行安全的假设非常有用的部分信任代码。与简单沙盒 CreateDomain API 沙箱成为更明显、 一致和安全 — 帮助使处理不受信任的所有事情变得更容易编写都代码。

实施

在这时我们有了适当的权限,授予我们部分信任程序集的集合,并已将程序集加载到适当的沙盒。很棒!但是,如果我们实际上要公开某些部分受信任的代码来提升功能?渚嬪我可能不希望授予对 Internet 应用程序的完整文件系统访问权限,但我 don’t 介意如果它读取和写入从已知的临时文件夹。

读取 Silverlight 安全 ( msdn.microsoft.com/magazine/cc765416.aspx ) 上的最后一年已经列人知道完全如何此问题处理在该平台 — 通过安全透明模型的整齐地拆分代码到三个存储桶。我 ’m 快乐假设模型的 Silverlight 已经晋升生效目前在.net Framework 4 上。这意味着更简单的模型都由 Silverlight 平台库的好处是现在的部分信任库的非 Microsoft 开发人员可用。我转到的和强制空间中的其他改进之前,但是,我讨论从前的我们主要强制机制。

在过去的强制

安全透明,实际上在.net Framework 2.0 中, 引入但主要为审核机制,而不是一项 (新的安全透明模型是两者) 强制提供服务,我提到过最后一年。在较旧的模型或级别 1 安全透明度,冲突是否不清单本身为硬故障 — — 它们 (如 p/调用到本机代码) 的许多导致权限需求。如果发生了变化透明的程序集在其授权集具有 UnmanagedCode,它可能仍继续操作并执行已执行的操作 (违反透明度规则,在进程中的)。此外,透明度检查停止在程序集边界,进一步减少及其强制效率。

LinkDemands 的形式附带在.net Framework 2.0 中的,则返回 true 强制 — 签的调用程序集授予一组所包含指定的权限的 JIT 时检查。所有不错,但实质上是此模型所需的库开发人员的审核和是多余的强制使用两个不同的机制。Silverlight 模型合并,并简化这些两个的概念已从此状态自然进展和变得什么现在是级别 2 安全透明。

级别 2 安全透明度

级别 2 安全透明度是强制机制的分隔符,则可以安全地在低信任环境中执行的代码和 isn’t 的代码。简而言之,它可以执行类似文件操作的安全敏感操作 (关键) 的代码和代码 can’t (透明) 之间绘制一个障碍。

安全透明模型将代码分为三个存储桶:透明、 安全关键和关键下面的图表 图 3 中,描述这些存储桶。(注:绿色箭头表示所允许的调用 ; 红色箭头代表那些 aren’t。self-loops 有效一样好但不是显示)


图 3 的 安全透明模型

对于典型桌面应用程序级别 2 透明度模型有没有明显的效果 — 不具有任何安全注释并不是沙盒代码假定为关键,因此它是不受限制。但是,因为它是关键,它是 off-limits 以部分信任调用方。因此,开发人员 don’t 部分信任方案 won’t 不必担心公开以部分信任的任何内容。

相反的沙盒的应用程序是如此 — — 任何程序集加载到沙盒应用程序域都假定 (即使它有注释,否则指定) 为完全透明。这确保了部分信任代码无法试图提升通过断言的权限或调用到本机代码 (一个完全信任等效操作)。

暴露在部分信任调用方与桌面或沙盒应用程序不同的库必须 keenly 注意其安全要求和对其能力和它们的公开具有更多的灵活性。典型的部分信任可调用库应该主要透明和关键代码使用最少的安全关键 api 集。关键代码时无限制,是已知为从部分信任代码无法访问。透明代码可从部分信任代码调用,但是安全的。安全关键代码是非常危险的因为它提供提升的功能和 utmost 必须小心以确保其调用方进行验证之前通过转换为关键代码。

安全透明属性和及其行为列出并 的 图 4 所述。请记住最高范围的属性适用于所有的引入 api 在它下, 无论这些 api 是否拥有其自己的注释。AllowPartiallyTrustedCallers 的不同,在于它交由来决定,并将尊重较低级别的属性。(注:此表描述了属性和它们的行为时应用于程序集、 类型或成员的级别。该属性仅应用于这意味着子类引入 api 和重写受限于继承规则,并且可能在不同的透明度级别)。

图 4 的 安全透明度特性和及其行为

请记住上次十月已经文章人可能会注意到属性工作,更多或更少,他们在 Silverlight 中相同的方式。您还可能记住了不同类型的代码与关联的特定的继承规则。这些也是在桌面中的效果。在继承规则和级别 2 透明度的其他方面的详细信息,请看一下最后一年已经文章 “ 安全的 Silverlight 2 ” ( msdn.microsoft.com/magazine/cc765416.aspx )。

条件 AllowPartiallyTrustedCallers

AllowPartiallyTrustedCallers 属性 (APTCA) 指示程序集是一个库,可能会公开安全敏感功能以部分信任。APTCA 库程序集通常写入结合与主机,因为主机通常要公开其宿主环境的特定功能。一个主要示例是公开要在各种信任级别可能是其托管代码 System.Web 命名空间的 ASP.NET。

但是,APTCA 放入 ’s 可用来决定在加载它的任何主机中的部分信任的程序集意味着,可以是一个责任如果程序集作者 doesn’t 知道该程序集在不同主机中的行为方式。因此,主机开发人员有时希望可用于部分信任只能在他们自己的域中加载时它们库。ASP.NET 不会完全这和在早期版本中都有必须要 LinkDemands 用于其 api 的特殊权限。尽管这适用于它会导致生成它们才能满足该 LinkDemand 防止从正在透明那些向上堆栈程序集具有顶部的每个人。

若要解决此问题,我们引入条件 APTCA 为功能允许仅在一个启用的主机 (通过列表) 中的部分信任调用方公开的 api 的库。

主机和库的特定角色是:

  • 库只是它限定带有一个参数 PartialTrustVisibilityLevel 枚举 AllowPartiallyTrustedCallers 属性。例如:
[assembly: AllowPartiallyTrustedCallers(PartialTrustVisibilityLevel= PartialTrustVisibilityLevel.NotVisibleByDefault)]
  • 此属性基本上说库不是可从部分信任调用只有该主机将具有它在其允许列表上,下面提到。 VisibleToAllHosts 的值会使库可调用从部分信任中的所有主机。

  • 主机指定程序部分信任可见集,每通过允许列表的应用程序域。 此列表通常是通过配置文件提供给该主机进行填充。 请记住一个重要的一点是无条件 APTCA 程序集 (如基本框架库没有的要添加到 (参阅重要要记住的是如果启用条件 APTCA 程序集,您应启用其传递闭包的依赖条件的 APTCA 程序集。 此列表。 否则,最终结果可能具有奇数行为根据您的原始程序集将尝试调用它假定是可访问的但实际上 aren’t 的 api)。

易于安全

对于.net Framework 4,很多具有安全模型中发生。 CAS 策略已被停用默认离开所有安全策略决策达主机及与本机 exe 授予 unhosted 的托管的 exe 行为奇偶校验。 禁用 CAS 策略已禁用异类应用程序域、 最后进行高效的简单沙盒 CreateDomain 重载部分信任程序集的主要支持的沙盒机制。 安全透明模型,描述最后十月的 Silverlight 已经改进有也逐渐在桌面上提供具有相同的效率和 cleanliness 好处到 Silverlight 平台提供的部分信任库开发人员。

我们精心设计如) 中的这些更改大多数应用程序将继续像他们有之前,但主机和库开发出存在将会发现一个更简单的模型,以处理工作的方式 — — 一个是更具有确定性、 使用更简单并因此,更方便地保证安全。

Andrew Dai 是 CLR 安全小组程序经理。 有关如何使用本文中提到的功能更多、 深入的信息,请访问 CLR 团队博客 ( blogs.msdn.com/clrteam ) 和 Shawn Farkas ’.net 安全日志 ( blogs.msdn.com/shawnfa )。