打造坚固的企业应用.NET 安全基础

打造坚固的企业应用.NET 安全基础 - 电脑安全 - 电脑教程网

打造坚固的企业应用.NET 安全基础

日期:2007-08-30   荐:
  托管代码的优点  开发 .NET Framework 应用程序提供了一些直接的安全性优点,但是还有许多问题需要考虑。这些问题在本指南第三部分的几个“构建……”单元中进行了讨论。    .NET Framework 程序集是用托管代码生成的。各种语言的编译器(例如 Microsoft Visual C#_ 开发工具和 Microsoft Visual Basic疇.NET 开发系统)都输出 Microsoft 中间语言 (MSIL) 指令,它们包含在标准 Microsoft Windows 可移植的执行文件 (PE) .dll 或 .exe 文件中。当加载程序集并且调用一个方法时,方法的 MSIL 代码将被实时 (JIT) 编译器编译为本机的机器指令,随后再执行这些机器指令。不会调用到的方法将不进行 JIT 编译。    中间语言与公共语言运行库所提供的运行库环境配合使用,为程序集开发人员提供了许多直接的安全性优点。    文件格式与元数据验证。 公共语言运行库能够验证 PE 文件格式的有效性,以及地址不指向 PE 文件之外。这有助于提供程序集独立。公共语言运行库还能验证程序集中所包含的元数据的完整性。    代码验证。MSIL 代码在进行 JIT 编译时会验证类型安全性。从安全角度来看,这是一个很大的优点,因为验证过程可以防止不良的指针操作,可以验证类型转换的合法性,检查数组边界,等等。这实际上消除了托管代码中出现缓冲溢出漏洞的可能,虽然仍旧需要仔细检查调用非托管应用程序编程接口 (API) 的代码是否存在缓冲溢出的可能。    完整性检查。强名称程序集的完整性需要使用数字签名来验证,以确保程序集从生成和签名之后没有发生任何改变。这意味着攻击者无法通过直接操作 MSIL 指令来改变代码。    代码访问安全性。公共语言运行库提供的虚拟执行环境还允许在运行时执行更多安全检查。说得具体一些,就是代码访问安全性能够根据调用代码的标识进行各种运行时安全决策。    用户安全性与代码安全性  用户安全性和代码安全性是 .NET Framework 应用程序中两种相辅相成的安全形式。用户安全性回答的是“用户是谁,用户能进行什么操作?”,而代码安全性回答的是这样的问题:“代码从何而来,谁编写了代码,代码能执行什么操作?” 代码安全性涉及的是授权对应用程序(而非用户)系统级资源(包括文件系统、注册表、网络、目录服务和数据库)的访问。在此情况下,无论最终用户是谁,或者哪个用户帐户运行代码都是无关紧要的,而什么代码以及是否允许进行这样的操作则非常重要。    .NET Framework 用户安全性的实现称为基于角色的安全性。 代码安全性的实现称为代码访问安全性。    基于角色的安全性  .NET Framework 基于角色的安全性允许 Web 应用程序根据与应用程序交互的用户的标识或者角色成员身份进行安全决策。如果应用程序使用 Windows 身份验证,则角色就是 Windows 组。如果应用程序使用其他形式的身份验证,则角色就是由应用程序定义的,用户和角色的详细信息通常维持在 SQL Server 或者基于 Active Directory 的用户存储中。    已经进行身份验证的用户的身份及其相关的角色成员身份是 Web 应用程序通过 Principal 对象获得的,后者附加在当前 Web 请求中。    图 1 显示了 Web 应用程序中如何使用用户安全性来限制用户访问 Web 页、业务逻辑、操作和数据访问的典型逻辑视图。     图 1. 基于(用户)角色的安全性的逻辑视图    代码访问安全  代码访问安全可以在代码试图访问安全的资源(例如,文件系统、注册表、网络等等)时,或者试图执行其他特权操作(例如,调用非托管代码或者使用反射)时,对其进行授权。    代码访问安全性是一种重要的附加防范机制,可以用来提供对一段代码的约束。管理员可以配置代码访问安全策略以限制代码能够访问的资源类型以及能够执行的其他特权操作。从 Web 应用程序的角度来看,这意味着如果在某个危及安全的攻击过程中,攻击者控制了 Web 应用程序进程或者插入了在进程中运行的代码,则代码访问安全性提供的这些附加约束就能够限制可能带来的损害。    图 2 显示了在 Web 应用程序中如何使用代码访问安全性来限制应用程序访问系统资源、其他应用程序拥有的资源和特权操作(如调用非托管代码)的逻辑视图。     图 2. 基于代码的安全性的逻辑视图      代码的身份验证(标识)是根据代码的证据(例如,它的强名称、发行者,或者安装目录)进行的。而授权是根据安全策略授予代码的代码访问权限进行的。有关 .NET Framework 代码访问安全性的详细信息,请参阅“代码访问安全性实践”单元。    .NET Framework 基于角色的安全性  .NET Framework 基于角色的安全性是在应用程序中用来授权用户操作的关键技术。角色经常用来强制执行一些业务规则。例如,财务应用程序可能只允许经理执行超过某个特定金额上限的转账操作。    基于角色的安全性由以下要素组成:    用户和标识    PrincipalPermission 对象    基于角色的安全性检查    URL授权    用户和标识  基于角色的安全性是通过 Principal 和 Identity 对象实现的。已进行身份验证的调用方的标识和角色成员身份是通过 Principal 对象公开的,该对象附加在当前 Web 请求中。可以使用 HttpContext.Current.User 属性检索该对象。如果应用程序不需要对调用方进行身份验证,例如,用户正在浏览站点中可以公开访问的部分,则 Principal 对象代表的是匿名 Internet 用户。    Principal 对象有很多类型,准确的类型取决于应用程序所使用的身份验证机制。但是,所有 Principal 对象都要实现 System.Security.Principal.IPrincipal 接口,它们都维持着一个角色列表,用户是其中的一个成员。     Principal 对象还包含 Identity 对象,后者包括用户名以及指示身份验证类型和用户是否已经进行身份验证的标志。这样就能够区分已进行身份验证和匿名的用户。Identity 对象也有许多不同类型,取决于身份验证的类型,虽然所有标识对象都要实现 System.Security.Principal.IIdentity 接口。    以下表格给出了可能的身份验证类型以及 ASP.NET Web 应用程序使用的 Principal 和 Identity 对象的各种不同类型。     PrincipalPermission 对象  PrincipalPermission 对象表示当前用户执行代码所必需的标识和角色。PrincipalPermission 对象可以在代码中声明性或命令性地使用。    声明性安全  可以通过在类或者方法定义中添加 PrincipalPermissionAttribute,准确地控制允许哪些用户访问这些类或者方法。类级别的属性自动应用于所有类成员,除非它已被成员级属性所重写。PrincipalPermissionAttribute 类型是在 System.Security.Permissions 命名空间中定义的。    注 还可以使用 PrincipalPermissionAttribute 限制对结构和其他成员类型(如属性和委托)的访问。    下面的示例说明了如何将对某个特定的类的访问权限制在 Managers 组的成员中。请注意该示例假设使用 Windows 身份验证,其中角色名的格式是 MachineName\RoleName 或者 DomainName\RoleName。对于其他的身份验证类型,角色名的格式是特定于应用程序的,并取决于用户存储中保存的角色名字符串。     [PrincipalPermissionAttribute(SecurityAction.Demand, Role=@"DOMAINNAME\Managers")]  public sealed class OnlyManagersCanCallMe  {  }    注 属性类型名中最后的 Attribute 可以省略。这样属性类型名就与其相关的权限类型名相同了,在此例中为 PrincipalPermission。它们是截然不同的(但逻辑上是相关的)类型。    下面的示例说明了如何限制对一个类的特定方法的访问。在此示例中,访问仅限于本地管理员组的成员,这是通过特殊的 "BUILTIN\Administrators" 标识符来标识的。     [PrincipalPermissionAttribute(SecurityAction.Demand,               Role=@"BUILTIN\Administrators")]  public void SomeMethod()  {  }    其他内置的 Windows 组名可以通过在组名前加上"BUILTIN\"(例如,"BUILTIN\Users" 和 "BUILTIN\Power Users" )使用。    命令性安全  如果方法级安全性对于您的安全需求来说还不够细致,可以在代码中执行命令性安全检查,方法是使用 System.Security.Permissions.PrincipalPermission 对象。    以下示例说明了使用 PrincipalPermission 对象的命令性安全语法。    PrincipalPermission permCheck = new PrincipalPermission(                  null, @"DomainName\WindowsGroup");  permCheck.Demand();    为了避免使用局部变量,以上代码还可以写成:     (new PrincipalPermission(null, @"DomainName\WindowsGroup")).Demand();    以上代码用一个空的用户名和指定的角色名创建了一个 PrincipalPermission 对象,然后调用了 Demand 方法。这将导致公共语言运行库查询附加于当前线程的当前 Principal 对象,检查相关联的标识是否为指定角色的成员。因为本例中使用了 Windows 身份验证,所以角色的检
标签: