CAS 代码访问安全性

系统 1645 0
前言:

用vs2005 + vsto 开发一个outlook的addin的时候,碰到了一个问题,在我机器上运行的好好的程序,用vs自己的打包安装程序安装到别的机器的时候总是显示 not load, 加载程序的时候出错。google了一下,遇到了一个新名词, CAS: code access security. 找不到相关的中文文档。在codeproject上看到了这篇文章。文章比较长,有codeproject的文风,讲解的非常详细,就是一点基础都没有的人都知道他说什么,但是要耐心看。 ^_^

Role Based Security (not being discussed in this article) 基于角色的安全验证

Code Access Security 代码访问安全性

CLR 允许代码做那些只被授权的行为,所以, CAS 是一种通过阻止未授权的访问来保护资源和操作的一种安全系统。运用 CAS ,你可以做到:

指定你的代码能够做的

指定那些代码可以代用你的代码

唯一标识你的代码

我们将在这篇文章讨论这些问题,你应该熟悉一些术语。

 

术语

 

CAS 包含一下这些元素:

  • permissions   许可

  • permission sets 许可集

  • code groups 代码组

  • evidence 物证

  • policy 策略

Permissions

Permissions 声明对受保护的资源的访问或者是执行受保护的操作的能力。 .Net Frameword 提供了一些 Permission 的类,像 FileIOPermission (对文件起作用), UIPermission (允许使用一些用户接口), SecurityPermission (对于执行代码甚至是绕过安全机制这是必须的)。我将不会列举所有的 Permission 类在这里,他们列举在下面。

Permission sets

一个 Permission Set 是一个 permission 的容器。你可以把 FileIOPermission UIPermission 放到你的 Permission set 中,然后叫他“ My_PermissionSet ”。一个 Permission set 可以包含许多 permissions FullTrust , LocalIntranet , Internet , Execution Nothing .net framework 内置的一些 permission sets FullTrust 包含所有的 permissions ,而 Nothing 则表示什么都不包括,甚至连执行的权利都没有。

Code groups

Code group 是一个特定条件下的代码逻辑组。 http://www.somewebsite.com/ 的代码可以属于一个代码组,包含一个特定的强类型名字的代码属于另一组,特定装配的代码又属于一个组。内置的代码组像 My_Computer_Zone , LocalIntranet_Zone , Internet_Zone 等等。像 permission sets, 我们可以创建代码组来满足我们基于 evidence 的需求。 Site , Strong Name , Zone , URL 是一些 evidence 的类型。

Policy

Security policy 是可配置的规则的集合,当我们决定赋予代码一定的许可。有 4 个机制的等级 Enterprise , Machine , User Application Domain ,每种操作不互相依赖。每个等级有它自己的 code groups permission sets 。他们的层次如下:


【图一】

Ok ,理论说完了,让我们把理论付诸实践。

 

小例子

 

让我们创建一个新的 windows 应用程序。添加 2 button 到存在的 form 上。我们将用到文件系统,所以添加 System.IO 命名空间。

    
      
        using
      
    
    
       System.IO;
      



【图二】

写下如下代码:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1   private   void  btnWrite_click( object  sender, System.EventArgs e)
{    
StreamWriter myFile  =   new  StreamWriter( " c:\\Security.txt " );   
myFile.WriteLine( " Trust No One " );   
myFile.Close();
}

private   void  btnRead_click( object  sender, System.EventArgs e)
{    
StreamReader myFile  =   new  StreamReader( " c:\\Security.txt " );   
MessageBox.Show(myFile.ReadLine());  
myFile.Close()
}


完整的版本号我们的例子才能够工作。确定你设置了你的版本号为一个固定的值,否则它会随着你的编译次数自动增加。我们标记这个装配用一个强名字,这将被用做 evidence 时标识代码用。这就是为什么你需要设置你的版本号为一个固定的值。

[assembly: AssemblyVersion( "<chsdate isrocdate="False" islunardate="False" day="30" month="12" year="1899" w:st="on">1.0.0</chsdate>.0" )]

就这样。。。没有什么异常。它将会写一个名字为 security.txt 的文件到 c:. 现在跑起来你的代码,它将会创建一个文件并写下一行,每件事看起来都 ok 。。。除非你没有 c 盘。现在我们要做的事把我们的装备到一个 code group ,并且设置一些 permissions 。还不要删除 security.txt 文件,我们晚点会需要它。

NET Configuration Tool

我们可以用两种方式来做这个工作,从 .NET Configuration Tool 或者是用命令行调用 caspol.exe 首先我们用 .NET Configuration Tool 。从控制面板——》管理工具-》 Microsoft .NET Framework Configuration 你也可以用“ mscorcfg.msc ”在 .net 命令行。你可以做很 cool 的事情通过这个工具。。但是目前我们只是对设置代码访问权限感兴趣。


【图三】

Creating a new permission set 创建一个新的 permission set

展开 runtime security policy 节点。你可以看到安全机制级别 Enterprise , Machine User 。我们将改变 Machine 机制的安全集合。首先我们创建我们自定义的 permission set 。右击 permission sets 节点选择 new 。因为我到别的易记住的名字,我命名它为 MyPermissionSet .


【图四】

我将在下一个屏幕添加 permissions permission set 。在左边的 panel ,我们可以看到 .NET Framework 支持的所有的 permissions 。现在我们得到 File IOpermission 属性。设置 File path c:\ 然后只选上 read 。所以我们没有赋予写的权限。请注意那里还有另一个选项说“准许装备自由的访问文件系统”如果这个被选上,任何事情都可以做,没有任何限制。


【图五】

现在我们多添加 2 p’ermissions Security User Interface 只需要添加记住添加“准许装备自由的访问文件系统”。我很快将会解释这些属性。没有 Security permission 。我们没有权限去执行我们的代码,没有 User Interface p’ermission ,我们将不会看到 UI 。如果你添加了这 3 permissions ,你会看到有一个新的 permission set 被创建,命名为 MyPermissionSet .

 

Creating a new code group 创建一个新的代码组

现在我们创建一个 code group 然后设置一些条件,所以我们的装配将会是这个 code group 的一员。注意在 code group 机电, All_Code 是父节点。右击 All_Code 节点选择 new 。创建 code group 向导将呈现在你面前。我将命名它为 MyCodeGroup .


    

【图六】

下一个屏幕,你需要提供一个 condition 类型给 code group 。这些就是之前提到过的 evidence 。在这个例子中,我们用 strong name 类型。首先标识你的装配用一个 strong name 然后编译它。现在我们按 import (导入)按钮选择你的装配。 Public key ,名字和版本将从装配中萃取出来,我们不需要考虑它。现在我们到下一个页面。我们必须为我们的 code group 指定一个 permission set 。因为我们已经创建了一个 MyPermissionSet , ,我们从 list box 中选他。


【图七】

Exclusive and LevelFinal

如果你还没有被。 NET configuration 默认的安全设置搞混淆,你的装配已经属于另一个内置的 code group My_Computer_Zone 。当 permission 被计算,如果一个特别的装配属于多个 code group 在相同的机制级别,最后的 permissions 将是所有的 code group permissions 的集合。我将晚点解释怎么计算 permissions ,现在我们只需要跑我们的装配用我们的 permission set ,就是用 MyPermissionSet 关联的 MyCodeGroup . 所以我们必须设置其他的属性来达到这个目的。右击新创建的 MyCodeGroup 节点选择属性。选择 check box " This policy level will only have the permissions from the permission set associated with this code group. " 这个机制等级的 permission 只包含与这个 code group 关联的 permission set 。这个叫 Exclusive 属性。如果这个被选上了,运行时将不会允许除关联到这个 code group permissions 。另一个选项叫做 LevelFinal . 这两个属性将在计算 permissions 的时候起作用,我们将详细解释它在下面。


【图八】

我们已经设置了许多属性,但是它将在最后讲得通。 :-<

 

好了,现在我们来跑我们得代码。我们现在做得就是把我们得代码放到一个 code group 中,并且给她对 c 盘得只读得权限,跑它并按那两个按钮, read 工作得很好,但是当你按 write 得时候,一个 exception 抛出了,因为我们没有对 c 盘写得权限。下面时出错得信息。


【图九】

所以多谢 code access security ,这种对资源得限制是可行的。通过 CAS 你可以做很多事情,我们讲在余下得文章中讨论。

Functions of Code Access Security

根据文档, CAS 充当了一下这些功能:(直接从文档上复制过来的)

  • Defines permissions and permission sets that represent the right to access various system resources.

  • Enables administrators to configure security policy by associating sets of permissions with groups of code ( code groups ).

  • Enables code to request the permissions it requires in order to run , as well as the permissions that would be useful to have , and specifies which permissions the code must never have .

  • Grants permissions to each assembly that is loaded, based on the permissions requested by the code and on the operations permitted by security policy.

  • Enables code to demand that its callers have specific permissions. Enables code to demand that its callers possess a digital signature, thus allowing only callers from a particular organization or site to call the protected code.

  • Enforces restrictions on code at run time by comparing the granted permissions of every caller on the call stack to the permissions that callers must have.

我们已经做了最顶上的 2 个,那是管理的部分。有一个独立的命名空间我们还没有看过 System.Security ,这个是用来实现安全的。

 

Security Namespace

System.Security 命名空间下的 主要的类有:

Classes

Description

CodeAccessPermission

定义下面的结构所有的代码访问权限

PermissionSet

申明一个包含不同 permissions 的集合

SecurityException

当检测到安全错误的时候抛出的异常

System.Security.Permissions 命名空间下的主要的类有 :

Classes

Description

EnvironmentPermission

控制对系统和用户环境变量的访问权限

FileDialogPermission

通过文件对话框控制对文件和文件夹的访问权限

FileIOPermission

控制对文件和文件夹的访问权限

IsolatedStorageFilePermission

指定对私有的虚拟文件系统的使用方式 .

IsolatedStoragePermission

指定对普通的独立存储的访问权限

ReflectionPermission

控制对 metadata 访问通过 System.Reflection APIs.

RegistryPermission

控制对注册表的访问

SecurityPermission

描叙安全的 permissions 应用到 code

UIPermission

控制 UI 和键盘的权限

你能找到更多的 permission 类 在其他的命名空间,例如, SocketPermission WebPermission System.Net SqlClientPermission System.Data.SqlClient 命名空间 , PerformanceCounterPermission System.Diagnostics 命名空间等等。

下一步,我们将看到怎么使用这些类。

Declarative vs. Imperative (声明和命令)

你在写代码的时候可以用两种不同的语法,声明和命令。

Declarative syntax 声明语法

生命语法用需要的安全信息属性去标识方法,类或者是装配。所以当编译的时候,他们替换相应的元数据章节。


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->  1   [FileIOPermission(SecurityAction.Demand, Unrestricted = true )]
 2  
 3   public  calss MyClass
 5   {
 7        public  MyClass() { }    //  all these methods
 9        public   void  MyMethod_A() { //  demands unrestricted access to 
11        public   void  MyMethod_B() { //  the file system
13   }
    
      

命令语法

命令语法用运行时方法调用创建一个新的实例。


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> public  calss MyClass 

{
    
public  MyClass() { }

    
public   void  Method_A() 
    {

        
//  Do Something

        FileIOPermission myPerm 
=  
          
new  FileIOPermission(PermissionState.Unrestricted);
        myPerm.Demand(); 
        
//  rest of the code won't get executed if this failed
 
        
//  Do Something
    }

    
//  No demands
     public   void  Method_B()
    {
        
//  Do Something
    }
}
    
      

他们 2 个的主要的不同是,声明调用是在编译的时候调用而命令调用是在运行时的时候。请 注意编译的时候指的是在 jit 编译的时候。

这里有一些行为可能与 permissions 冲突。


首先,我们看一下声明的语法。用 UIPermission 来说,声明语法意思使用属性,所以我们实际使用 UIPermissionAttribute ,当你打开 msdn 你会看到这些属性:

  • Action - SecurityAction 枚举的一个值

  • Unrestricted – 自由访问

  • Clipboard – 对键盘的访问权限, UIPermissionClipboard 枚举的一个值 (UIPermission specific)

  • Window – 对窗体的访问权限 UIPermissionWindow 的一个值。

Action Unrestricted 属性是通常类的 permission Clipboard Window 用来指明 UIPermission 。你必须提供 action 你使用其他属性的你用到的 permission 类。所以在这种情况下,你可以像这样写:


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> [UIPermission(SecurityAction.Demand,
Clipboard
= UIPermissionClipboard.AllClipboard)]
    
      

或者添加 Clipboard Window 两个属性:


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> [UIPermission(SecurityAction.Demand,
    Clipboard
= UIPermissionClipboard.AllClipboard, 
      Window
= UIPermissionWindow.AllWindows)]
    
      

如果你想要声明一个 permission 用自由访问,你可以这样做:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> [UIPermission(SecurityAction.Demand, Unrestricted = true )]

当你使用命令语法,你可以使用构造函数来传递这些值,然后在属性中调用它的 action 。我们用 RegistryPermission


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> RegistryPermission myRegPerm  =  
   
new  RegistryPermission(RegistryPermissionAccess.AllAccess,
   
" HKEY_LOCAL_MACHINE\\Software " );
myRegPerm.Demand();
    
      

如果你想自由访问这些资源,你可是使用 PermissionState 枚举用如下的方法:


<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> RegistryPermission myRegPerm  =   new  
RegistryPermission(PermissionState.Unrestricted);
myRegPerm.Demand();

这是你调用任何 permissions 类所需要知道的在 .NET Framework. 。现在,我们将详细讨论 actions

Security Demands

需求用来保证每一个调用你代码的调用者(间接的或者是直接的),已经得到需要的 permission 。这个通过一个栈来完成。什么 ... 一个老鼠道?不,那是你女朋友做的,我的意思是一个栈道。请求一个 permission ,运行时安全系统浏览栈,比较每个调用者准许的 permissions 和被请求的 permission 。如果任何一个调用栈不能找到请求的 permission ,然后 SecurityException 抛出。请看如下的图:


图十】

不同的装配和不同的方法在相同的装配通过栈道来检查。

现在回到需求。这里有 3 种类型的需求。

  • Demand

  • Link Demand

  • Inheritance Demand




CAS 代码访问安全性


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论