Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西

导航

可怕的 Fully Trusted Code

Posted on 2004-07-08 10:58  Flier Lu  阅读(2262)  评论(0编辑  收藏  举报
http://www.blogcn.com/user8/flier_lu/index.html?id=1601113&run=.01EAE25

  Keith Brown在4月份的MSDN杂志上发表了一篇讨论.NET下安全性的文章,Beware of Fully Trusted Code,其中详细讨论了让 Managed Code 允许在 Fully Trusted 模式下的危害。真是不看不知道,呵呵,现在我是深深感到了 Fully Trusted Code 的可怕。:D

     对一个类型的私有成员变量来说,其私有性的保护实际上只是编译期的
 

以下为引用:

 class DiskQuota {
 private:
   long MinBytes;
   long MaxBytes;
 };
 

    
     以上类型的私有成员变量实际上可以简单的通过unsafe代码中的指针操作访问
 
以下为引用:

 void EvilCode(DiskQuota* pdq) {
    // use pointer arithmetic to index
    // into the object wherever we like!
    ((long*)pdq)[1] = MAX_LONG;
 }    
 

    
     好在CLR能够通过类型系统完整性检测,一定程度上解决这类有意或缓冲区溢出的问题,除非在程序中显式的要求CLR关闭此类检测。如
 
以下为引用:

 // evilcode.cs
 using System.Security.Permissions;

 [assembly: SecurityPermission(
    SecurityAction.RequestMinimum,
    Flags=SecurityPermissionFlag.SkipVerification)]

 // your evil code goes here
 


    
     麻烦的是一旦使用/unsafe参数编译C#程序,或者使用Managed C++编写程序,这个权限就被隐式地设置为最低,以保障代码地正确执行。虽然新版本的C#编译器将提供参数选项打开此权限,但最根本的解决方法还是得通过.NET安全策略来完成。可惜在缺省状态下,本地硬盘上的Managed程序都是在 Fully Trusted 模式下运行的。
     可以通过控制面板的管理工具中的"Microsft .NET Framework 1.1配置"工具,在 我的电脑运行库安全策略计算机代码组All_Code 上通过 编辑代码组属性 看到当前的安全策略设置。安全策略一般分为企业、计算机和用户三级,每级又可根据一定的代码组条件分为多个代码组,设置不同的权限集。
     我们接下来看看 Fully Trusted 权限的“威力”所在吧 :P
     
     首先是所谓的私有方法,众所周知它们是可以通过Reflection被直接调用的,呵呵,如下:    
 
以下为引用:

 using System;
 using System.Reflection;

 class EvilCodeWithFullTrust
 {
   static void CallPrivateMethod(object o, string methodName) {
     Type t = o.GetType();
     MethodInfo mi = t.GetMethod(methodName,
        BindingFlags.NonPublic |
        BindingFlags.Instance);
     mi.Invoke(o, null);
   }
   static void Main() {
     CallPrivateMethod(new NuclearReactor(), "Meltdown");
     }
 }
 


    
     比较好的解决方法是通过检测调用者是否被信任,来保障私有函数不被滥用,如使用StrongNameIdentityPermission属性限制调用者所在assembly必须有相同的public key,可以参见我以前的一篇 BLog 文章《关于信任粒度的讨论》
 
以下为引用:

 public class NuclearReactor {
   [StrongNameIdentityPermission(
     SecurityAction.LinkDemand,
     PublicKey="002400000...")]
   private void Meltdown() {
     // calling assembly must have specified public key!
   }
 }
 

    
     这样可以禁止直接通过Reflection访问私有成员函数或变量。但如果调用者代码具有 Fully Trusted 权限的话,它可以直接使用命令行工具 caspol -s off 或者通过代码,完全关闭 StrongNameIdentityPermission 进行的检测,呵呵
 
以下为引用:

 using System.Security;
 class EvilCodeWithFullTrust {
   static void Main() {
     SecurityManager.SecurityEnabled = false;
     // now call Meltdown via reflection!
   }
 }
 

    
     改变SecurityManager.SecurityEnabled的值需要SecurityPermissionFlag.ControlPolicy权限,对应于配置中安全性下的允许策略控制权限, Fully Trusted 情况下是打开的 :(
     
     既然系统自动的调用者验证可以被跳过,是否能通过程序手工进行验证呢?以下代码在调用不可完全信任的插件之前,通过降低权限来限定插件的能力,可以说这是一种非常好的安全编程习惯。
 
以下为引用:

 using System.Security;
 using System.Security.Permissions;

 class WellMeaningCode {
   public void CallPlugIn(EvilCode plugin) {
     // put a CAS modifier on the stack that denies all file system access
     new FileIOPermission(
       PermissionState.Unrestricted).Deny();
     plugin.DoWork();
     CodeAccessPermission.RevertDeny();
   }
 }
 


    
     但是在 Fully Trusted 权限下还是无能为力,直接对PermissionSet.Assert函数的调用使得权限检查再一次被跳过。
 
以下为引用:

 class EvilCodeWithFullTrust {
   void DoWork() {
     new PermissionSet(
       PermissionState.Unrestricted).Assert();
     // happily access the file system
     // regardless of the caller's deny!
       }
 }
 

     前面提到配置工具中对安全策略的配置有企业、机器和用户三层,实际上还有AppDomain这一层,可以通过AppDomain.SetAppDomainPolicy载入单独的安全策略限定其后需要执行的代码,ASP.NET就是通过这种方法限定执行代码的权限。但是具有 Fully Trusted 权限的代码可以打破 AppDomain 边界的限制,并可以通过调用其他 Unmanaged Code 实现对其他 AppDomain 侵入。好在可以通过修改 machine.config 文件让 ASP.NET 运行在较低的权限集中,如
 

以下为引用:

 <configuration>
   <system.web>
     <securityPolicy>
       <trustLevel name="Full" policyFile="internal" />
       <trustLevel name="High" policyFile="web_hightrust.config" />
       <trustLevel name="Medium" policyFile="web_mediumtrust.config" />
       <trustLevel name="Low" policyFile="web_lowtrust.config" />
       <trustLevel name="Minimal" policyFile="web_minimaltrust.config" />
     </securityPolicy>
     <!--  level="[Full|High|Medium|Low|Minimal]" -->
     <trust level='Medium'/>
   </system.web>
 </configuration>
 

    
     但因为很多程序员没有耐心完成最小权限集的调整工作,导致大部分情况下为了省事将缺省权限设置为 Fully Trusted,导致上述各种精心设计的安全检测都形同虚设。再好的技术如果没有相应的管理来保障,只是摆设而已。
     解决这个问题,一方面需要程序员对其代码的权限做限定和调整,另一方面需要开发厂商提供静态和动态的权限分析工具辅助,最后还得配合传统的NT权限设置来把关,毕竟CLR还是运行在NT的用户的权限集下。
     
     有兴趣的朋友可以进一步阅读这篇文章:Writing managed code for semi-trusted environment
     
     此外 Brown 还是 Programming Windows Security 一书的作者,他在书中详细介绍了 Windows 环境下的安全子系统的运行机制和使用方法,并一定程度上涉及到了网络认证、COM+和Internet环境下的安全性问题,非常详尽值得一读。此书已经由电力出版社翻译出版 《Windows安全性编程》