执行不受信任的代码

Posted

技术标签:

【中文标题】执行不受信任的代码【英文标题】:Executing untrusted code 【发布时间】:2010-03-13 12:51:41 【问题描述】:

我正在构建一个使用插件的 C# 应用程序。应用程序必须向用户保证插件不会在用户机器上为所欲为,并且具有比应用程序本身更少的权限(例如,应用程序可以访问自己的日志文件,而插件不能) .

我考虑了三种选择。

    使用 System.AddIn。我首先尝试了这个替代方案,因为它非常强大,但是每次我想要修改某些东西时,我都需要在七个不同的项目中修改七次相同的代码,这让我感到非常失望。此外,即使是一个简单的 Hello World 应用程序,也有大量的问题需要解决。

    使用 System.Activator.CreateInstance(assemblyName, typeName)。这是我在之前版本的应用程序中使用的。我再也不能使用它了,因为它没有提供限制权限的方法。

    使用 System.Activator.CreateInstance(AppDomain 域,[...])。这就是我现在要实现的,但似乎唯一的方法是通过 ObjectHandle,这需要对每个使用的类进行序列化。虽然插件包含 WPF 用户控件,但它们是不可序列化的。

那么有没有办法创建包含 UserControl 或其他不可序列化对象的插件并使用自定义 PermissionSet 执行这些插件?

【问题讨论】:

【参考方案1】:

您可以做的一件事是将当前 AppDomain 的策略级别设置为受限权限集,并添加证据标记以根据强名称或位置进行限制。最简单的可能是要求插件位于特定目录中并为它们提供限制性策略。

例如

public static void SetRestrictedLevel(Uri path)

    PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();            

    // Create simple root policy normally with FullTrust
    PolicyStatement fullPolicy = new PolicyStatement(appDomainLevel.GetNamedPermissionSet("FullTrust"));
    UnionCodeGroup policyRoot = new UnionCodeGroup(new AllMembershipCondition(), fullPolicy);

    // Build restrictred permission set 
    PermissionSet permSet = new PermissionSet(PermissionState.None);            
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));            
    PolicyStatement permissions = new PolicyStatement(permSet, PolicyStatementAttribute.Exclusive);
    policyRoot.AddChild(new UnionCodeGroup(new UrlMembershipCondition(path.ToString()), permissions));            

    appDomainLevel.RootCodeGroup = policyRoot;

    AppDomain.CurrentDomain.SetAppDomainPolicy(appDomainLevel);


static void RunPlugin()

    try
                    
        SetRestrictedLevel(new Uri("file:///c:/plugins/*"));                

        Assembly a = Assembly.LoadFrom("file:///c:/plugins/ClassLibrary.dll");
        Type t = a.GetType("ClassLibrary.TestClass");
        /* Will throw an exception */                
        t.InvokeMember("DoSomething", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
                null, null, null);
     
     catch (Exception e)
     
         Console.WriteLine(e.ToString());
     

当然,这并没有经过严格测试,而且 CAS 政策非常复杂,因此始终存在此代码可能允许某些事情绕过政策的风险,YMMV :)

【讨论】:

以上是关于执行不受信任的代码的主要内容,如果未能解决你的问题,请参考以下文章

将不受信任的java代码限制为单个线程[重复]

当执行太多不受信任的代码时,除去令人讨厌的大量 trycatch 的办法

防止不受信任的 C# 代码启动新线程或黑名单/白名单 API

保护/清理不受信任的客户端对服务器的远程调用

URL 重定向到不受信任的站点

服务器证书不受信任怎么解决