.NET 框架安全性概述

本文深入探讨了Microsoft .NET框架的安全系统,包括基于角色的安全性、验证、代码访问安全性、堆栈审核等核心概念。文章指出,.NET框架提供了一个强健的安全系统,允许代码在管理员定义的安全上下文中运行,同时支持动态下载和执行。.NET的安全模型不仅与用户和角色关联,还对代码本身进行安全性控制。文章详细解释了验证过程、代码访问安全性如何根据证据分配权限,以及堆栈审核如何确保代码执行的安全性。此外,文章还介绍了声明性安全和命令性安全的使用方式,以及基于角色的安全性,强调了代码标识与用户标识之间的区别。
摘要由CSDN通过智能技术生成

简介

传统的程序开发模式中,管理员通常将软件安装到本地磁盘的一个固定位置;当从这种模式转向支持动态下载和执行、甚至支持远程执行的环境时,安全性是要考虑的一个最重要的因素。为了支持这种模式,Microsoft .NET 框架提供了一个强健的安全系统,该系统可以限制代码在严格约束的、管理员定义的安全上下文中运行。本文研究了 .NET 框架中的一些基本的安全性特性。

许多安全模型将安全性与用户和它们的组(或角色)关联起来。这就意味着,用户和代表这些用户运行的所有代码或者被允许对重要资源执行操作,或者不被允许执行操作。在大多数操作系统中安全性都是按照这种模型构建的。.NET 框架提供了一种开发人员定义的安全模型,称为基于角色的安全性,它也是按照这种类似的结构运行的。基于角色的安全性的主要抽象是 Principals 和 Identity。此外,.NET 框架也在代码上提供了安全性,这种安全性称为代码访问安全性(也称为基于证据的安全性)。使用代码访问安全性,某个用户可能会获得信任以访问某个资源,但是如果用户执行的代码不受信任,则访问资源也会被拒绝。与基于特定用户的安全性对比,基于代码的安全性是允许安全性得以在可移动代码 (mobile code) 上体现的一个基本工具。可移动代码可能会由任意数量的用户下载和执行,而所有这些用户在开发时都是不了解的。代码访问安全性主要集中于一些核心的抽象,它们是:证据、策略和权限。基于角色的安全性和代码访问安全性的安全抽象是用 .NET 框架类库中的类型来表示的,而且是用户可扩展的。这里有两个值得注意的挑战:以一致和连贯的方式向一些编程语言公开安全模型,以及保护和公开 .NET 框架类库中代表资源(使用这些资源可能会导致安全性破坏)的类型。

.NET 框架安全系统是在传统操作系统安全性上层运行的。这种方式在操作系统安全性上又增加了一层更具表现力和可扩展的安全性。这两层安全性相互补充。(操作系统安全系统也可以将一些责任委托给托管代码的公共语言运行库安全系统,因为该运行库安全系统比传统的操作系统安全性粒度更细,可配置性也更强。)

本文提供了 .NET 框架安全性方面的一个概述,具体讲述了基于角色的安全性、验证、代码访问安全性和堆栈审核方面的内容。并且使用一些小的编程示例揭示一些概念。本文没有论及其他的运行库安全工具,如加密和独立存储。

顺便提一下,本文通常描述的是上面这些安全特性的默认行为。然而 .NET 框架安全系统具有极强的可配置性和极强的可扩展性。这就是该系统的一个主要优点,但遗憾的是,在这篇概念性描述的文章中不能详细地对这一点进行讨论了。

执行概述

运行库既执行托管代码,又执行非托管代码。托管代码是在运行库的控制下执行的,因此可以访问运行库提供的服务,如内存管理、实时 (JIT) 编译,以及本文涉及的最重要的安全性服务(如安全策略系统和验证)。非托管代码是经过编译、要运行在特定硬件平台上的代码,它不可直接利用运行库。然而,当语言编译器生成托管代码时,该编译器的输出是以 Microsoft 中间语言 (MSIL) 表示的。MSIL 通常被描述为一种用于抽象的、基于堆栈计算机、面向对象的伪汇编语言。之所以说 MSIL 是面向对象的,是因为它有一些支持面向对象概念的指令,如对象分配 (newobj) 和虚函数调用 (callvirt)。之所以说是抽象的计算机,是因为 MSIL 不依赖于任何特定的平台。就是说,它对于在其上运行的硬件不会作出任何假设。它之所以是基于堆栈的,是因为从本质看,MSIL 是通过向堆栈压入 (push) 值和从中弹出 (pop) 值以及调用方法来执行的。MSIL 通常会在执行前被实时编译为本机代码。(MSIL 也可以在运行该代码前编译为本机代码。这有助于缩短程序集的启动时间,但是 MSIL 代码通常是在方法级别进行 JIT 编译的。)

验证

在运行库会进行两种形式的验证:MSIL 验证和程序集元数据验证。运行库中的所有类型都指定了它们将要实现的协定,这些信息将作为元数据与 MSIL 一起保留在托管 PE/COEFF 文件中。例如,如果一个类型指定它从另一个类或接口进行继承,这就表明它将要实现一些方法,这就是一个协定。协定也可以与可见性联系起来。例如,可以将类型声明为从它们的程序集公开(导出)或其他的内容。因为类型安全只能根据它们的协定访问类型,所以就此而言,它是代码的一个属性。可以验证 MSIL 以证明它是类型安全的。验证是 .NET 框架安全系统中的一个基本构造块,目前只在托管代码上执行验证。因为非托管代码不可由运行库进行验证,所以由运行库执行的非托管代码必须是完全受信任的。

为了理解 MSIL 验证,关键在于理解如何对 MSIL 进行分类。MSIL 分为下列类型:无效的 MSIL、有效的 MSIL、类型安全的 MSIL 以及可验证的 MSIL。

应该指出的是,下面的定义比标准定义提供了更多信息。有关更加准确的定义版本,请参阅其他文档,如 ECMA standard

无效 MSIL 是 JIT 编译器不能为它生成本机表示的 MSIL。例如,不可将包含无效操作码的 MSIL 翻译成本机代码。另一个示例是跳转指令,该指令的目标是操作数的地址,而不是操作码。

有效 MSIL 可以被认为是满足 MSIL 语法的所有 MSIL,因此它可以用本机代码表示。这种分类包括这样的 MSIL,即,使用非类型安全形式的指针算法获取对类型成员的访问的 MSIL。

类型安全 MSIL 只通过它们的向公众公开的协定与类型交互。试图从一个类型中访问另一个类型的私有成员的 MSIL 就不是类型安全的。

可验证 MSIL 是可以通过一个验证算法来证明是类型安全的 MSIL。验证算法比较保守,因此一些类型安全的 MSIL 可能不会通过验证。可验证 MSIL 自然既是类型安全的又是有效的,当然不是无效的。

除了类型安全检查之外,运行库中的 MSIL 验证算法还会检查堆栈上溢/下溢的发生、异常处理工具的正确使用以及对象初始化。

对于从磁盘加载的代码,验证过程是 JIT 编译器的一部分,它会在 JIT 编译器中间歇性地进行。验证和 JIT 编译不是作为两个独立的进程来执行的。如果验证期间在程序集中找到了一连串不可验证的 MSIL,那么安全系统就会检查该程序是否足够受信任,可以跳过验证。例如,如果一个程序集是在安全模型的默认设置下从本地硬盘上加载的,那可能就是这样的情况。如果程序集受信任可跳过验证,MSIL 则会翻译成本机代码。如果程序集的受信任程度不够,不可跳过验证,则会用一个存根来代替有问题的 MSIL,如果使用了该执行路径,该存根就会引发一个异常。一个常见的问题是:“为什么不在验证程序集之前检查它是否需要验证呢?”因为验证通常是作为 JIT 编译的一部分执行的,所以它通常比检查是否允许程序集跳过验证更快。(决定跳过验证比这里描述的过程更加智能。例如,可以缓存前面一些验证尝试的结果,以提供快速的查找方案。)

除了 MSIL 验证之外,还要验证程序集元数据。事实上,类型安全依赖于这些元数据检查,因为它假定 MSIL 验证期间使用的元数据标记是正确的。在全局程序集缓存 (GAC) 或下载缓存中加载程序集时,会验证程序集元数据;如果没有将它插入到 GAC 中,则从磁盘中读取它时也会验证程序集元数据。(GAC 是由一些程序使用的程序集的中央存储。下载缓存保存了从其他位置(如 Internet)下载的程序集。)元数据验证包括检查元数据标记和消除缓冲区溢出,前者用于检查它们是否会正确索引到它们访问的表中,以及到字符串表的索引是否并不指向长度大于应该保存它们的缓冲区大小的字符串。通过 MSIL 验证和元数据验证消除非类型安全的类型安全代码是运行库上安全性的第一部分。

代码访问安全性

从本质上讲,代码访问安全性根据程序集证据向程序集分配权限。在决定代码对哪些资源应该有访问权限时,代码访问安全性会使用可执行代码从中取得的位置和有关代码标识的其他信息作为一个主要因素。有关程序集标识的信息称为 证据。一旦将程序集加载到运行库用于执行时,宿主环境就会向程序集附加一些证据。运行库中的代码访问安全系统负责将这些证据映射到一个权限集,该权限集又将决定此代码对一些资源(比如注册表或文件系统)具有什么访问权限。这种映射是以可管理的安全策略为基础的。

对于托管代码的大多数应用程序方案,所设计的默认代码访问安全性策略是安全而且是足够的。它严格地限制了来自不完全受信任或不受信任环境(如 Internet 或本地 Intranet)的何种代码在本地计算机上执行时能够运行。因此代码访问安全性默认策略模型代表着通往安全的一种可行途径。默认情况下资源是安全的;管理员需要采取显式的操作才能使得系统安全性稍差一些。

我们为什么还需要另一种安全方案呢?与用户标识相对,代码访问安全性是以代码标识为中心的。这使得代码可以在一个用户上下文中,以无限数量的信任级别运行。例如,即使运行其中的操作系统用户上下文允许完全访问所有系统资源,来自 Internet 的代码也只能在限定的安全边界中运行。

现在让我们来看一下代码访问安全系统的主要输入和输出:证据和权限。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值