.NET安全编程 阅读笔记

一: 权限

    所谓权限, 既代码能否运行或访问一定资源的资格. 而所谓权限的制定, 则是制定一系列框架或对应关系, 从而定义什么样的代码, 或怎么运行的代码具有什么样的资格. dot net framework 包括CAS(code access security)这个重要的功能, 能为托管代码的操作和访问资源提供精细的控制. 使用CAS访问是基于代码表示而不是用户运行. 同时, CAS提供了一套灵活的可扩展框架, 既使用权限的对象来定义和强制执行代码的安全性. 权限对象可以实现以下目标:

    1. 当运行库载入程序集时, 它会为程序集分配权限对象, 该对象代表了运行库授予程序集的权力.

    2. 保护程序集想要调用的资源或代码, 即要求调用系统资源或代码的程序集具备一定的权限. 运行库在载入程序集时会授予每一个程序集一组权限对象, 当程序集的代码调用库成员时, 库就会使用权限对象来要求运行库保证调用的程序集具有同等权限.

 

运行库基于程序集标识来决定授予程序集哪组权限, 运行库使用两种不同的机制将证据转化成权限:

    1. 运行库通过比较基于 dot net 安全策略的程序集的证据,在一个名为策略解析的进程里来决定授予程序集哪组代码访问权限.

    2. 实现System.Security.Policy.IidentityPermissionFactory接口的任意宿主证据都会导致运行库授予程序集一个标识权限.该权限代表了证据的类型和值.

    当调用程序集时, 运行库载入程序集,计算其证据并决定授予它哪些权限, 同时,运行库还需要保证, 不仅即时调用方具有指定权限, 而且整个调用链也都具有必要的权限, 这样才能保证高权限代码不会被低权限代码调用从而执行它本来没有权限做的事情, 此时运行库将进入堆栈并检查权限.

 

编程代码访问的安全性.

    1. 强制性安全语句: 强制性安全语句出现在方法体或函数体中, 通常使用Demond()方法. 对于上面讲到的堆栈中的权限检查, 通常使用Assert, Deny 和PermitOnly方法. 强制性安全检查的语法大致如下:

  1. public void CreateFile()
  2. {
  3.  FileIOPermission perm = new FileIOPermission(
  4.  FileIOPermissionAccess.Write,@"C:\SomeFile.txt");
  5.  try{
  6.  perm.Demand();
  7.  }
  8.  catch(Exception ex)
  9.  {
  10.  //someting  
  11.  }
  12. }

    2. 声明性安全语句: 使用属性来声明安全语句. 对每一种代码访问和标识权限类而言, .net类库都包含了相应的属性类. 它们能表示该权限的声明性安全语法. 如FileIOPermission类的相应属性是FileIOPermissionAttribute. 同时对于属性的Attribute还可以省略. 声明性安全支持的操作选择比强制性安全支持的要多一些. 具体例子如下:

  1. [FileIOPermission(SecurityAction.Demand,Write=@"C:\SomeFile.txt")]
  2. public void CreateFile(){
  3. \\content
  4. }

.NET 提供如下的代码访问权限类:

DBDataPermission: 这是一个抽象基类, 能为数据提供程序权限类的基本功能.

OdbcPermission: 通过ODBC数据提供程序来控制访问数据源.

OleDbPermission: 通过OLE DB数据提供程序来控制访问数据源.

OraclePermission: 通过Oracle数据提供程序来控制访问Oracle数据库.

SqlClientPermission: 通过SQL客户数据提供程序来控制访问Microsoft SQL Server数据库.

EventLogPermission: 控制对Windows事件日志的访问.

PerformanceCounterPermission: 控制对Windows性能计数器的访问.

DirectoryServicesPermission:控制对目录服务的访问, 如Active Directory.

PrintingPermission:控制对打印机的访问.

DnsPermission: 控制对基于网络的域名服务器的访问.

WebPermission: 控制对Internet资源的访问.

SocketPermission: 控制对基于套接字的网络通信的访问.

MessageQueuePermission:控制对Microsoft消息列的访问.

EnvironmentPermission: 控制对读入,创建和改变环境变量的访问.

FileDialogPermission: 通过限制标准Windows文件对话框的可访问性机器功能来控制访问文件和文件夹.

FileIOPermission: 通过限制创建,改变或删除文件或文件夹来控制访问本地硬盘.

IsolatedStoragePermission: 控制对隔离存储的访问.

ReflectionPermission: 控制对运行库提供的访问.

RegistryPermission: 控制对Windows注册表的访问.

ResourcePermissionBase: 一个抽象基类, 为Windows面向资源的权限类提供公共功能.

SecurityPermission: 控制对一组安全功能的访问, 该功能与应用程序域,策略,证据, 线程, 原则, 执行, 构造,.net远程配置, 序列化, 确认和非托管代码有关.

UIPermission:控制对操作用户界面和剪贴板的访问.

ServiceControllerPermission: 控制对Windows服务入口的访问.

AspNetHostingPermission(1.1): 控制对ASP.NET--宿主环境的访问.

 

此外, 每种标准代码访问权限类还存在完全限制状态和非完全限制状态.由PermissionState枚举确定. 其值为None时,表示完全限制状态, 即没有任何权限, 其值为Unrestricted时,表示非完全限制状态. 如非完全限制状态的FileIOPermission代表可以访问本地硬盘驱动的所有文件和目录.而完全限制的FileIOPermission则代表不能访问它们. 不过值得注意的是, SecurityPermission 的Unrestricted设置无效.

 

编程权限集

当实现代码的CAS功能的时候, 通常可能会用到不止一个权限,这个时候,可以考虑应用编程权限集.PermissionSet. 通过AddPermisson方法,添加需要的权限, 之后,可以调用PermissionSet的Demand方法提出安全要求.它内部会调用Permission的Union方法,合成一个之后,再调用其Demand方法.此外,利用PermissionSet还可以应用集合的并与交去计算两个PermissionSet之间的权限.

 

编程权限请求

简单来说, 即写在程序集中, 希望运行库能够给予的权限.当运行库载入一个程序集时,它会计算权限的请求, 并使用声明性安全语法来表示该请求, 因为权限请求定义了程序集的安全要求,因此必须使用程序集范围属性来声明. 这并不能改变程序集本身的权限,但是可以提供很多便利,如可以方便的让用户或安全管理员查看程序集需要的权限(Permview.exe),以便作出必要部署. 权限请求分别被SecurityAction枚举所代表:RequestMinimum, RequestOptional和RequestRefuse.

    1. 最小权限请求 RequestMinimum, 如果想要编写能访问偶组权限的代码来实现正确的功能, 最好的办法就是给程序集配置最小权限请求, 特别是当代码要求的权限不是默认安全策略通常授予的权限的时候.配置方法如下:

  1. [assembly:FileIOPermission(SecurityAction.RequestMinimum,Read=@"c:\config")]
  2. [assembly:FileIOPermission(SecurityAction.RequestMinimum,All=@"c:\development")]

以上代码示范了如何申请最小权限保证读取C:\config和对C:\development目录的完全访问.

    2. 可选权限请求 RequestOptional. 该请求指定了最大权限组, 尽管有安全策略配置,运行库也应该授予程序集最大权限组, 如果不能授予RequestOptional语句指定的所有权限,运行库也能被载入, 但是运行库绝不会授予比制定权限更多的权限.

    3. 拒绝权限 RequestRefuse. 保证指定的权限不会被授予程序集. 以下方法是用一个非限制性的FileIOPermission来拒绝访问所有的文件及文件夹.

  1. [assembly:FileIOPermission(SecurityAction.RequestRefuse,Unrestricted=true)]

除了Demand之外, LinkDemands和InheritanceDemand也可以执行权限请求, 此处不再详细介绍.他们都可以应用到类或个体功能性成员如方法属性和事件中.如果使用声明性语法在类声明上制定了一个Demand, 每个类成员都会被强制执行同样的Demand, 为了重写个体成员的Demand, 只需在其上简单制定不同的Demand即可.

 

操作堆栈步

在某些实例中, 可能需要使用重写堆栈步的方法来改变默认的堆栈对于安全的相应方式.CAS支持三种不同的堆栈步重写方法:Assert, Deny和PermitOnly.

     1. Assert: 如果编写访问受保护资源或操作的代码, 期望安全策略授予调用你编写代码的代码具有同样级别的权限是不合理的, 也就是说有时候可能会需要允许低级别的代码调用高级别的代码去做一些事情.(这一点并不知道是否是原书所要表达的意思.) 而Assert则提供这样一种保证.表示此处的权限级别.在堆栈步中,如果权限符合要求或者它是断言权限的子集,那么堆栈步就会在断言方法的堆栈框架处成功终止. 假设MethodB方法调用MethodD方法删除硬盘上的一个文件.且MethodB方法断言了一个非限制性的FileIOPermission. 当MethodD调用静态System.IO.File.Delete方法来删除文件时, Delete会发出一个可写的安全请求.假设MethodD有必要的权限, 则当堆栈步进入MethodB的堆栈框架时, 它会比较要求的FileIOPermission和断言的非限制性的FileIOPermission.因为写入文件是非限制性FileIOPermission的子集,如果调用堆栈上的所有调用方都被证实具有要求的权限,则堆栈步就会终止.

如果引发堆栈步的安全要求被某个程序集调用,且断言的权限只是部分满足安全要求,堆栈步就会继续, 但是剩余的堆栈框架智慧与Assert不满足的权限子集作对比. 以下是断言非限制性FileIOPermission实例:

ContractedBlock.gif ExpandedBlockStart.gif Code

public void MethodB(){
 
try{
  FileIOPermission p 
= new FileIOPermission(PermissionState.Unrestricted);
  p.Assert();
 }
 
catch(SecurityException se)
 {
 }
}

应该注意的是, 在使用Assert方法之前, 应该确保代码不能被恶意代码作为通道来访问受保护资源, 因为Assert重写方法经常在高度信任的权限中使用, 而不是每个应用程序都会被授予高度信任,因此, 要慎用此方法,以免为运行库的总体安全性打开缺口.

     2. Deny: 与Assert相反, 运行库不是针对堆栈之上的调用方的权力的证明, 也不是针对使用积极响应来终止堆栈步的证明, 而是对初始化Demand和终止堆栈步的代码引发SecurityException. 针对上面的例子, 若MethodB拒绝了一个非限制性的FileIOPermission, 这会使得任何试图访问硬盘中的堆栈步失败.当MethodD执行时, 会发出安全要求,要求对要删除的文件可写, 假设堆栈步进入MethodB, 它会比较要求的FileIOPermission和拒绝的非限制性FileIOPermission. 因为前者是后者的子集.因此会引发异常. 声明方法类似于Assert方法.

     3. PermitOnly类似于Deny的例外, 制定允许堆栈步继续运行的权限.从而拒绝其他意外的权限.

转载于:https://www.cnblogs.com/feixuezheng/archive/2009/01/05/1369296.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值