代码访问安全(code-access security)

 

.NET 安全性 (security) 提供了两种安全模型,一个是code-access security (简称 CAS) ,另外一个是role-based security,前者是用来控制程序的行为,后者是用来控制使用者的行为。而本文讲的是CAS

CAS让开发者和管理员可以实现对代码有权访问的那些资源进行精确的控制,它也被称为evidence-based security

1.   概述

.Net Framework提供了机制来控制代码能访问的资源(主要是指那些重要的需要保护的资源,比如注册表,文件系统,打印机等等)。

1.1. 证据(Evidence

在允许代码运行前,.Net Framework必须知道代码的身份以及来源。而Evidence就是一组关于Assembly的身份和来源的信息。证据可以是 CLR 所提供,也可以由 assembly 自行提供,可以属于 assembly,也可以属于 AppDomain。当CLR加载assembly的时候它使用CLR Host(比如windows shell hostasp.net hostIE host)提供Evidence.Net Framework 安全系统,.Net Framework 安全系统根据这些证据进行授权(MSDN中那些继承了CodeAccessPermission的类,就能知道有那些权限)。

Evidence(证明、证据)包括的信息为:

(1)       Assembly的强名称(strong name)——唯一的公钥(public key)、assembly名称和版本(version)。

(2)       Assemblycryptographic hash

(3)       Assembly的发行者,这可以通过微软的Authenticode  signature来检查。

(4)       Zone of assembly originate——可以是 InternetLocal IntranetTrusted Site (信任的网站)Untrusted SiteMy Computer

(5)       Code Location——可以是URLUNCUniversal Naming Convention)和本地文件夹路径。

 

另外,还可以自定义Evidence,但前提是安全策略配置为使用自定义Evidence

Evidence还有强弱之分。比如使用了strong nameAuthenticode  signatureassembly是拥有强Evidenceassembly,因为strong name不容易伪造,除非发行者的私钥被破解。强Evidenceassembly也被认为是其可信任度高的。

1.2. 安全策略(Security Policy

安全策略允许终端用户或者管理员根据得到的证据来控制授予代码的权限等级。说白了,就是根据收集到的Evidence来决定授予什么使用权限。.Net Framework中内建了很多代码访问权限类(那些继承了CodeAccessPermission的类),用来保护系统资源。当然,我们也可以自定义这样的类来实现自定义权限。一个安全策略使一个特定类型的证据(Evidence)和一个权限集合(有很多预设的权限集合:NotingExecutionInternetLocalIntranetEverythingFullTrust)相对应。

.NetPolicy分为四级(这些Policy都是以xml文档的方式存储在计算机上的,使用.NET Framework Configuration工具可以很方便地修改这些策略的设定,另外还有一个命令行工具——caspol.exe),每个层级下都含有一个树型结构的Code Group。这四个层级为:

(1)       Enterprise Policy——由企业的管理员来定义的安全策略,对应的xml文件为\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\enterprisesec.config

(2)       Machine Policy——由本计算机的管理员定义的安全策略,对应的xml文件为\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\security.config

(3)       User Policy——由用登录户定义的安全策略,对应的xml文件为此用户路径下的 ApplicationData\Microsoft\CLR Security Config\vXXXX\security.config

(4)       Application Domain Policy——由CLR Host定义的安全策略,无对应的xml文件。此策略通常用来一个AppDomain中的代码去访问访问另外一个AppDomain,是在创建AppDomain的时候一次性设定的,此后就不允许修改了。

1.3. 代码组(Code Group

security policy类似,一个Code GroupEvidence和权限集合对应起来——在一个代码组中,就拥有此组的权限。Code Group就是一个对满足一定成员资格条件的代码的逻辑分组。使用.NET Framework Configuration工具可以查看到有哪些Code Group,而且可以看到每个组都有三个主要内容:名称、成员资格条件和使用权限集合。

1.4. 安全策略如何确定权限分配的结果?

做法是:取交集。

.NET CLR 会将 assembly和代码组进行比较,若证据符合要求,就可以获得该群组的使用权限集合,并继续往下一个阶层比较。若不符合代码组的条件,则不能获得该群组的使用权限集,同时停止向下一层做比较,最终取的是权限集合的交集。

1.5. 修改安全策略的需要

对于开发者和测试人员来说:

(1)       验证应用的功能是否可以运行在设定的安全策略之下。

(2)       测试安全方面的Features

对于部署者和系统管理员来说:

(1)       应用安全最佳实践。

(2)       方便部署。

2.   执行基本的安全操作

2.1. 什么是Permission Demand?

Permission Demand就是用来防止一个低权限的assembly通过调用高权限的assembly来提升自己的权限。.Net FrameworkSecurity System通过遍历调用堆栈(Walking Stack)来检查每个调用者的权限,从而保护资源安全。举一个例子来说:assembly A调用了assembly Bassembly B又调用了assembly C,如果c使用了Demand方法,那在c执行的时候,CLR不仅会检查assembly C的权限,还要检查assembly Aassembly B的权限。

2.2. 什么是Permission Assert?

对于某代码A,在确保A的调用者不会滥用代码A来访问资源的情况下,为了保证即使A的调用者没有权限也能通过调用代码A来使用资源,可以使用Assert方法来令.Net FrameworkSecurity System停止安全检查。

2.3. 其它的安全检查

除了上面讲的安全检查方法DemandAssert外,还有其它一些安全检查方法,比如:

DenyPermitOnlyRevertAssertRevertDenyRevertPermitOnlyRevertAll等等,各位可以去查阅MSDN。

3.   执行命令式安全操作

3.1. 使用命令式Demand方法

1.  Create a new instance of a permission object.

2.  Set the properties that you want on the permission object.

3.  For most permission objects, you can set the properties in a single call to the

constructor.

4.  Call the Demand method of the method.

5.  In most instances, the Demand method is called in a try block, so if the

demand fails, the resulting exception is caught.

6.  If the demand fails, SecurityException is thrown. Otherwise, the call

succeeds and execution continues after the call.

代码:

FileIOPermission filePerm = new

FileIOPermission(FileIOPermissionAccess.Read,

"C:\\testfile.txt");

try

{

filePerm.Demand();

// if demand succeeds, execution continues here

}


catch (SecurityException se)

{

// if demand fails, execution continues here

}



3.2. 如何使用命令式Assert方法

例子:

EnvironmentPermission envPerm = new EnvironmentPermission(

EnvironmentPermissionAccess.Read,

"NUMBER_OF_PROCESSORS");

envPerm.Assert();


4.   执行宣告式安全操作

4.1. 如何使用宣告式安全检查方法

所谓宣告式,就是使用Attribute的方式。需要注意的是命令式和宣告式不能使用在同一个方法中。

例子:

[FileIOPermission(SecurityAction.Demand, Read = "C:\\TEMP")]

public class MyNewClass

{

.

[EnvironmentPermission(SecurityAction.Demand,

Read 
= "USERNAME")]

public void MyMethod()

{

.

}


}

 

4.2. 什么是身份权限(Identity Permission?

就是使用Evidence来作为一个Assembly的身份。根据其身份来赋予一定的权限。

4.3. Link Demand

就是要求直接调用者必须有足够的权限,是在JIT期间执行检查。LinkDemand在一个公司需要保证只有自己开发的Assembly才能被调用的情况下非常有用。

[StrongNameIdentityPermission(

SecurityAction.LinkDemand, PublicKey 
= "12789ADE",

Name 
= "MyApp", Version = "1.0.0.0")]

public class MyNewClass

{

// MyNewClass can only be called by the assembly

// with the strong name specified in the attribute

}


 

4.4. Inheritance Demand

此方法要求派生类要继承基类或者覆盖基类的方法所需要的权限。

例子:

[CustomPermission(SecurityAction.InheritanceDemand)]

public class MyNewClass

{

public MyNewClass()

{

}


[CustomPermission(SecurityAction.InheritanceDemand)]

public virtual string ReadData()

{

//Access a custom resource

}


}


 

5.   添加Permission Requests

5.1. 什么是Permission Request?

Permission Request定义了一个assembly请求使用、能够使用和不应该使用的权限。

有三类:

(1)       RequestMinimum——assembly需要的最小权限。

(2)       RequestOptional——assembly可选的权限,可有可无的权限。

(3)       RequestRefused——assembly不能拥有的权限。

例子:


[assembly:FileIOPermissionAttribute(SecurityAction.RequestMini
mum, Write
="C:\\test.txt")]
[assembly:PermissionSet(SecurityAction.RequestOptional,Unrestr
icted
=false)]

5.2. 添加Permission Requestassembly

通过添加assembly级别的Attribute来添加permission request

[assembly:SecurityPermission(
SecurityAction.RequestMinimum, UnmanagedCode 
= true)]

[assembly:PermissionSet(
SecurityAction.RequestMinimum, Name 
= "FullTrust")]

 

6.   总结

1、  CLR在执行某assembly前,会检查assemblyEvidence(身份和来源),然后根据安全策略的设定,授予此assembly一定的执行权限。

2、  安全策略是分层次(Level)的,和代码组一起形成一个树状结构,安全策略最终取每个层次的交集来确定权限。.Net提供了很多的Policy Level,这点据说是比Java要强的。

3、  而安全检查方法提供了一种精细的控制方式。Demand安全检查方法是最强的一种,它告诉CLR去检查整个调用链上的每个方法的权限;而LinkDeman只检查直接调用者的权限,这非常适合于使用的组件是本公司自己开发的场合。另外还有Assert方法等等,使用中需要注意可能存在安全漏洞。

希望大家阅读此文后,在编写代码时能时刻考虑到安全性问题,防止自己的代码被恶意者滥用。

posted @ 2005-08-01 10:08  风满袖  阅读(4570)  评论(14编辑  收藏  举报