执行不受信任的代码

发布于 2024-08-25 09:04:35 字数 607 浏览 5 评论 0原文

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

我考虑了三种选择。

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

  2. 使用System.Activator.CreateInstance(程序集名称,类型名称)。这是我在应用程序的先前版本中使用的。我再也不能使用它,因为它没有提供限制权限的方法。

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

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

I'm building a C# application which uses plug-ins. The application must guarantee to the user that plug-ins will not do whatever they want on the user machine, and will have less privileges that the application itself (for example, the application can access its own log files, whereas plug-ins cannot).

I considered three alternatives.

  1. Using System.AddIn. I tried this alternative first, because it seamed much powerful, but I'm really disappointed by the need of modifying the same code seven times in seven different projects each time I want to modify something. Besides, there is a huge number of problems to solve even for a simple Hello World application.

  2. Using System.Activator.CreateInstance(assemblyName, typeName). This is what I used in the preceding version of the application. I can't use it nevermore, because it does not provide a way to restrict permissions.

  3. Using System.Activator.CreateInstance(AppDomain domain, [...]). That's what I'm trying to implement now, but it seems that the only way to do that is to pass through ObjectHandle, which requires serialization for every used class. Although plug-ins contain WPF UserControls, which are not serializable.

So is there a way to create plug-ins containing UserControls or other non serializable objects and to execute those plug-ins with a custom PermissionSet ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

橘寄 2024-09-01 09:04:35

您可以做的一件事是将当前 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 :)

One thing you could do is set the current AppDomain's policy level to a restricted permission set and add evidence markers to restrict based on strong name or location. The easiest would probably be to require plugins are in a specific directory and give them a restrictive policy.

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());
     }
}

Of course this isn't rigorously tested and CAS policy is notoriously complex so there is always a risk that this code might allow some things to bypass the policy, YMMV :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文