ITPub博客

首页 > 应用开发 > IT综合 > CLR中代码访问安全检测实现原理(转)

CLR中代码访问安全检测实现原理(转)

原创 IT综合 作者:RegisterForBlog 时间:2007-09-19 18:45:09 0 删除 编辑
CLR中代码访问安全检测实现原理(转)[@more@]

  在传统的操作系统级安全模型中,安全管理的粒度都是 Principal-based 层面的。用户从认证登陆成功开始,就获得此帐号的所有权限,而其运行的程序,也自动被授予帐号及其所在组的所有权限。例如我在《DACL, NULL or not NULL》一文中介绍的,NT 用户从登陆到系统建立 Session 开始,就缺省使用相同权限,新建进程自动获得父进程的权限,除非程序本身手动进行限制。而 *nix 系统下面的思路也是类似,只不过从 Token 编程了各种 uid/gid 等等。

  这种 Principal-based 的安全模型,在以主机为中心的孤立环境中是非常合适的,而且足够简单和高效。但随着网络的普遍使用,这种安全模型开始受到挑战,最直接的就是如何处理从网络上运行程序的策略问题。按照现有模型,所有程序都会自动获得最大权限集,但这显然是不现实的,安全管理粒度过于粗放。

  因此在 Java 和 IE 等涉及网络的应用程序中,提出了新的基于位置的安全模型。一个程序运行时获得的权限,并不由其父进程或者说宿主来决定(这些程序往往用于较高权限),而是由其程序所在位置觉得具有多少权限。Java 中将之简化为对代码源的安全策略限定,如在策略文件中指定所有来自 www.nsfocus.com 的程序都有写 c: emp 目录的权限,而来自其他网址的程序只能读取 c: emp 目录内容。而 IE 中则更进一步,将这些来源分类为本机(my computer)、内网(intranet)、外网(internet)、可信站点(trusted)和不可信站点(untrusted)。

  如果说 Principal-based 的安全模型中,关键因素是:我是谁(当前帐号)、我要访问什么(目标资源)、我要怎么访问(操作类型);则在 基于位置的安全模型中变成了:我来自哪里(代码来源)、我要访问什么(目标资源)、我要怎么访问(操作类型)。关键因素虽然只有一个我是谁到我来自哪里的转变,但其控制粒度能够大大提升。

  但是这样的基于位置的安全模型还是存在其问题,因为组件之间的可信程度是不同的。例如一个本机控件因为来源于本机,受到系统的信任,被赋予很高的权限。同时一个恶意代码来源于不受信任的位置,无法执行某项操作。如果权限限定完整的话,本来不会出现问题,但因为某些权限依赖关系的管理混乱,造成恶意代码可以通过受信任代码执行本不应允许他执行的功能。这也是众多 IE 相关漏洞的问题根本所在,其受到 IE 现有安全模型的单级信任机制的限制,注定无法彻底解决。

  要彻底解决此类问题,归根结底必须建立一个可信链验证机制,也就是说执行某个操作的时候,必须检查此操作所有的上级操作组件是否拥有安全权限,而不仅仅只检测最后一级的组件。这一思路正是 CLR 中代码访问安全检测的设计思路,其关键因素增加了一个:调用我的人都有哪些,他们是否有相应权限的检测。

  例如我在建立一个文件的时候,可以强制性检测调用链上的所有组件是否都拥有操作此文件的权限:

  以下内容为程序代码:

  public void CreateFile()

  {

  // Create a new FileIO permission object

  FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Write, @"C:SomeFile.txt");

  try {

  // Demand the FileIOPermission

  perm.Demand( );

  } catch (SecurityException se) {

  // Callers do not have necessary permission

  }

  // Method implementation...

  }

  FileIOPermission 类描述了我需要检测的权限,对 C:SomeFile.txt 文件可写;FileIOPermission.Demand() 则执行这一权限的检测工作,遍历此方法调用链上的所有组件,检测他们是否有次权限。这样一来就可以从理论上避免恶意代码通过调用可信组件执行越权操作的问题。具体的权限定义和使用方法,这里就不详细介绍了。下面就这种检测如何实现做一个结构上的简要分析。

  System.Security.CodeAccessPermission

  System.Security.Permissions.EnvironmentPermission

  System.Security.Permissions.FileDialogPermission

  System.Security.Permissions.FileIOPermission

  System.Security.Permissions.ReflectionPermission

  System.Security.Permissions.RegistryPermission

  System.Security.Permissions.SecurityPermission

  System.Security.Permissions.UIPermission

  System.Security.Permissions.IsolatedStoragePermission

  System.Security.Permissions.IsolatedStorageFilePermission

  System.Security.Permissions.StrongNameIdentityPermission

  System.Security.Permissions.PublisherIdentityPermission

  System.Security.Permissions.SiteIdentityPermission

  System.Security.Permissions.UrlIdentityPermission

  System.Security.Permissions.ZoneIdentityPermission

  为进行代码访问权限检测,CLR 缺省定义了以上这些权限类型。首先他们都是从 CodeAccessPermission 类型继承出来,其次就其意义可进一步分为代码访问权限和代码身份权限。代码访问权限定义代码将如何去访问资源,如读写文件、弹出对话框等等;代码身份权限则定义访问此资源的组件必须符合什么样的身份,如只能是本地文件、或者只能是 nsfocus.com 发布的组件等等。

  虽然权限种类众多,但各种子类只负责定义自身权限的特性以及如何对自身权限验证,而所有的调用链遍历和验证工作,都是由 CodeAccessPermission.Demand() 方法完成的:

  以下内容为程序代码:

  public void CodeAccessPermission.Demand()

  {

  CodeAccessSecurityEngine engine = SecurityManager.GetCodeAccessSecurityEngine();

  if ((engine != null) && !this.IsSubsetOf(null))

  {

  StackCrawlMark mark = StackCrawlMark.LookForMyCallersCaller;

  engine.Check(this, ref mark);

  }

  }

  可以看到 CodeAccessPermission.Demand 方法,实际上是将验证操作转发给安全管理器 SecurityManager 的代码访问安全引擎 CodeAccessSecurityEngine 类型的 Check 方法完成的。

  以下内容为程序代码:

  internal class CodeAccessSecurityEngine

  {

  internal virtual void Check(CodeAccessPermission cap, ref StackCrawlMark stackMark)

  {

  if (!PreCheck(cap, null, 1, ref stackMark, PermissionType.DefaultFlag))

  {

  Check(PermissionToken.GetToken(cap), cap, ref stackMark, -1, ((cap is IUnrestrictedPermission) ? 1 : 0));

  }

  }

  internal virtual void Check(CodeAccessPermission cap, ref StackCrawlMark stackMark, PermissionType permType)

  {

  int num1 = 0;

  if (CodeAccessSecurityEngine.GetResult(permType, out num1))

  {

  return;

  }

  if (this.PreCheck(cap, null, 1, ref stackMark, permType))

  {

  CodeAccessSecurityEngine.SetResult(permType, num1);

  return;

  }

  this.Check(PermissionToken.GetToken(cap), cap, ref stackMark, -1, ((cap is IUnrestrictedPermission) ? 1 : 0));

  }

  [MethodImpl(MethodImplOptions.InternalCall)]

  private void Check(PermissionToken permToken, CodeAccessPermission demand, ref StackCrawlMark stackMark, int checkFrames, int unrestrictedOverride);

  }

  CodeAccessSecurityEngine 内部类的 Check 方法,将最终调用通过 Unmanaged 代码实现的内部方法进行安全检测。rotor 中的 COMCodeAccessSecurityEngine 类型 (ComCodeAccessSecurityEngine.cpp) 实现了这个检测逻辑。

  COMCodeAccessSecurityEngine::Check 函数 (ComCodeAccessSecurityEngine.cpp:683) 通过调用 COMCodeAccessSecurityEngine::CheckInternal 函数 (ComCodeAccessSecurityEngine.cpp:697) 填充一个堆栈遍历请求结构 CasCheckWalkData 的内容,最终将请求转发给 StandardCodeAccessCheck 函数 (ComCodeAccessSecurityEngine.cpp:563) 完成检测。此结构的指针将作为堆栈遍历回调函数的参数传递给回调函数进行实际权限验证,而 StandardCodeAccessCheck 只是负责调用全局堆栈遍历支持 StackWalkFunctions 函数(StackWalk.cpp:512),以 CodeAccessCheckStackWalkCB 函数 (ComCodeAccessSecurityEngine.cpp:449) 为回调函数,以 CheckInternal 函数填充的 CasCheckWalkData 结构为参数,通过现成的堆栈遍历支持 Thread::StackWalkFrames 完成堆栈遍历。

  通过堆栈遍历实现代码访问安全检测调用流程如下:

  以下为引用:

  CodeAccessSecurityEngine::Check 内部调用定义,由下面的函数实现

  COMCodeAccessSecurityEngine::Check 转发检测请求 (ComCodeAccessSecurityEngine.cpp:683)

  COMCodeAccessSecurityEngine::CheckInternal 填充 CasCheckWalkData 结构 (ComCodeAccessSecurityEngine.cpp:697)

  StandardCodeAccessCheck 执行堆栈遍历

  Thread::StackWalkFrames 遍历当前线程堆栈

  CodeAccessCheckStackWalkCB 检测当前组件权限 (ComCodeAccessSecurityEngine.cpp:449)

  因此现在 CAS 检测的问题被分为两个部分:如何遍历调用堆栈;如何检测某个组件是否拥有权限。

  过于如何遍历调用对象,因为涉及到比较复杂的堆栈帧类型处理,这里

  

本文来自:http://www.linuxpk.com/30600.html

-->linux电子图书免费下载和技术讨论基地

·上一篇:透析黑客攻击技术之渗透防火墙的Shellcode

·下一篇:SYMANTEC防火墙内核溢出漏洞利用之安全返回
 
     最新更新
·注册表备份和恢复

·低级格式化的主要作用

·如何防范恶意网站

·常见文件扩展名和它们的说明

·专家:警惕骇客骗局,严守企业信息

·PGPforWindows介紹基本设定(2)

·解剖安全帐号管理器(SAM)结构

·“恶作剧之王”揭秘

·绿色警戒

·黑客反击战

·网络四大攻击方法及安全现状描述

·可攻击3种浏览器代码流于互联网

·黑客最新的兴趣点,下个目标会是谁?

·“僵尸”——垃圾邮件的主要传播源

·Lebreat蠕虫惊现3变种

·POSTFIX反病毒反垃圾Ų…

·在FreeBSD上用PHP实现在线添加FTP用户

·简单让你在FreeBSDADSL上…

·安全版本:OpenBSD入门技巧解析

·Internet连接共享上网完全攻略

·关于ADSL上网网速常识

·静态缓存和动态缓存的比较

·最友好的SQL注入防御方法

·令网站提速的7大秘方

·网络基础知识大全

·路由基本知识

·端口映射的几种实现方法

·VLAN经典诠释

·问题分析与解决——ADSL错误代码

·问题分析——关于2条E1的线路绑定


关于我们 | 联系方式 | 广告合作 | 诚聘英才 | 网站地图 | 网址大全 | 友情链接 | 免费注册

Copyright © 2004 - 2007 All Rights Reserved

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10763080/viewspace-970148/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论