代码改变世界

安全探索——.NET 中的角色安全(4)

2009-02-23 11:11 by G yc {Son of VB.NET}, ... 阅读, ... 评论, 收藏, 编辑

在前面的文章中, 我已经介绍完了.NET 内部 Identity 和 Principal 类型了(再来就是我没有发现的了)。那么这回说说 PrincipalPermission 对象。

不过,在这之前,先说一下 CAS(代码访问安全)。

代码访问安全

代码访问安全性是帮助限制代码对受保护的资源和操作的访问权限的一种机制。在 .NET Framework 中,代码访问安全性执行下列功能:

  • 定义权限和权限集,它们表示访问各种系统资源的权限。
  • 使管理员能够通过将权限集与代码组关联来配置安全策略。
  • 使代码能够请求运行所需权限以及其他一些有用的权限,以及指定代码绝对不能拥有哪些权限。
  • 根据代码请求的权限和安全策略允许的操作,向加载的每个程序集授予权限。
  • 使代码能够要求其调用方拥有特定的权限。
  • 使代码能够要求其调用方拥有数字签名,从而只允许特定组织或特定站点的调用方来调用受保护的代码。
  • 通过将调用堆栈上每个调用方所授予的权限与调用方必须拥有的权限相比较,加强运行时对代码的限制。

简单来说,CAS设计主旨是尽可能的使用最低的必要权限来保证安全。CAS通过在检查调用方法的堆栈的权限来决定是否可以继续执行,或者请求必要的权限,而拒绝掉多余的权限。其必要权限,可以让代码正常执行。在一般的程序中,这可能没有什么问题,也不会带来什么影响, 但如果程序是支持扩展,比如运行了第三方程序集,这个时候,就可能会出现恶意的操作。但由于没有足够权限,因此程序会抛出异常,恶意程序也就无法执行了。

有关更多的 代码访问安全性

CAS调用的对象就是Permission 对象,他们都在 System.Security.Permissions 命名空间 下(大部分)。下面的说的也是在这里。

PrincipalPermission 对象

PrincipalPermission 类 是用来为声明和强制安全性操作定义的语言结构来检查活动用户。

即使通过检查当前线程的Principal对象,来确定是否有权限继续执行。

可以以命令方式和声明方式进行的安全检查均可使用 PrincipalPermission 类。

以命令方式实现 PrincipalPermission 类,创建该类的一个新实例,并用希望用户在访问代码时具有的名称和角色来初始化该实例。例如,以下代码以“"Joan"”身份和“"Teller"”角色对此对象的一个新实例进行初始化。

 

Dim id As String = "Joan" 
Dim role As String = "Teller" 
Dim principalPerm As New PrincipalPermission(id, role)

 

可使用 PrincipalPermissionAttribute 类以声明方式创建一个类似的权限。以下代码以声明方式将身份初始化为“Joan”,并将角色初始化为“Teller”。

 

<PrincipalPermissionAttribute(SecurityAction.Demand, Name := "Joan", Role := "Teller")>

 

执行安全检查时,为成功完成检查,指定的身份和角色必须匹配。但是,创建 PrincipalPermission 对象时,可传递一个 null 身份字符串以指示主体的身份可以是任意的。同样,传递一个 null 角色字符串指示主体可以是任何角色的成员(或根本不属于任何角色)。对于声明的安全性,可通过省略两种属性之一来获得相同的效果。例如,下列代码使用 PrincipalPermissionAttribute 以声明方式指示主体可以具有任意名称,但必须具有出纳的角色。

 

<PrincipalPermissionAttribute(SecurityAction.Demand, Role := "Teller")>

 

 

 

组合 PrincipalPermission 对象

 

在大多数情况下,使用 PrincipalPermission 对象的方法与使用代码访问安全性权限对象的方法相同。但是,权限功能的某些方面要比其他方面更有用。例如,可以调用 Intersect 方法使两个 PrincipalPermission 对象相交,但这可能不会很有用,因为标识和角色单独相交以返回表示相交对象的公共标识和角色的 PrincipalPermission 对象。在许多情况下,返回的对象包含表示身份、角色或同时表示两者的空字符串,并且此对象仅与未经过身份验证的用户匹配(身份 = "")或与不属于任何角色的用户匹配(角色 = "")。

子集操作决定某个 PrincipalPermission 对象是否是另一个 PrincipalPermission 对象的严格意义上的子集。从效率上讲,这意味着仅当身份和角色完全匹配时,或角色和身份两者之一为 null 时,IsSubsetOf 才返回 true。因此,对于此权限而言,使用 IsSubsetOf 的效率具有局限性。

另一方面,当希望以简洁的方式表示要测试的一组条件时,对两个 PrincipalPermission 对象执行联合操作可能是有用的。例如,如果希望检查一种身份或另一种身份是否存在时,可以使用联合操作。以下代码显示一个当 Principal 对象表示 Administrator 角色中的 fred 或 sally 时取得成功的安全检查。

 

Dim id1 As String = "fred" 
Dim role1 As String = "Administrator" 
Dim myPrincipalPerm1 As New PrincipalPermission(id1, role1) 
Dim id2 As String = "sally" 
Dim role2 As String = "Administrator" 
Dim myPrincipalPerm2 As New PrincipalPermission(id2, role2) 
myPrincipalPerm1.Union(myPrincipalPerm2).Demand()

 

以下代码显示如何指定两个权限的联合,这两个权限接受任何具有上述代码中的 role1 和 role2 值的主体。

 

Dim pp1 As New PrincipalPermission(Nothing, role1) 
Dim pp2 As New PrincipalPermission(Nothing, role2) 
pp1.Union(pp2).Demand()