执行不受信任的代码

时间:2010-03-13 12:51:42

标签: serialization plugins appdomain permissionset

我正在构建一个使用插件的C#应用​​程序。应用程序必须向用户保证插件不会在用户计算机上执行任何操作,并且具有应用程序本身的较少权限(例如,应用程序可以访问其自己的日志文件,而插件则不能)

我考虑了三种选择。

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

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

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

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

1 个答案:

答案 0 :(得分:1)

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

e.g。

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:)