【问题标题】:Restrict plugin access to file system and network via appdomain限制插件通过 appdomain 访问文件系统和网络
【发布时间】:2009-08-31 12:28:22
【问题描述】:

前段时间我问过如何限制插件访问(我想阻止它们写入磁盘或网络),我被告知使用AppDomain。我已经搜索并尝试过如何使其正常工作但失败了。

任何人都可以提供一些信息以便我可以开始,只需创建一个不允许写入文件或网络的 AppDomain。

【问题讨论】:

    标签: c# appdomain


    【解决方案1】:

    对于.net framework 4.0,请按照this MSDN文章中的以下代码。

    以下示例实现了上一节中的过程。在示例中,Visual Studio 解决方案中名为 Sandboxer 的项目还包含名为 UntrustedCode 的项目,该项目实现类 UntrustedClass。此方案假定您已下载一个库程序集,其中包含一个预期返回 true 或 false 以指示您提供的数字是否为 Fibonacci 数字的方法。相反,该方法会尝试从您的计算机中读取文件。以下示例显示了不受信任的代码。

    using System;
    using System.IO;
    namespace UntrustedCode
    {
        public class UntrustedClass
        {
            // Pretend to be a method checking if a number is a Fibonacci
            // but which actually attempts to read a file.
            public static bool IsFibonacci(int number)
            {
               File.ReadAllText("C:\\Temp\\file.txt");
               return false;
            }
        }
    }
    

    以下示例显示了执行不受信任代码的 Sandboxer 应用程序代码。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Security;
    using System.Security.Policy;
    using System.Security.Permissions;
    using System.Reflection;
    using System.Runtime.Remoting;
    
    //The Sandboxer class needs to derive from MarshalByRefObject so that we can create it in another 
    // AppDomain and refer to it from the default AppDomain.
    class Sandboxer : MarshalByRefObject
    {
        const string pathToUntrusted = @"..\..\..\UntrustedCode\bin\Debug";
        const string untrustedAssembly = "UntrustedCode";
        const string untrustedClass = "UntrustedCode.UntrustedClass";
        const string entryPoint = "IsFibonacci";
        private static Object[] parameters = { 45 };
        static void Main()
        {
            //Setting the AppDomainSetup. It is very important to set the ApplicationBase to a folder 
            //other than the one in which the sandboxer resides.
            AppDomainSetup adSetup = new AppDomainSetup();
            adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);
    
            //Setting the permissions for the AppDomain. We give the permission to execute and to 
            //read/discover the location where the untrusted code is loaded.
            PermissionSet permSet = new PermissionSet(PermissionState.None);
            permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    
            //We want the sandboxer assembly's strong name, so that we can add it to the full trust list.
            StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();
    
            //Now we have everything we need to create the AppDomain, so let's create it.
            AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);
    
            //Use CreateInstanceFrom to load an instance of the Sandboxer class into the
            //new AppDomain. 
            ObjectHandle handle = Activator.CreateInstanceFrom(
                newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
                typeof(Sandboxer).FullName
                );
            //Unwrap the new domain instance into a reference in this domain and use it to execute the 
            //untrusted code.
            Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();
            newDomainInstance.ExecuteUntrustedCode(untrustedAssembly, untrustedClass, entryPoint, parameters);
        }
        public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)
        {
            //Load the MethodInfo for a method in the new Assembly. This might be a method you know, or 
            //you can use Assembly.EntryPoint to get to the main function in an executable.
            MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);
            try
            {
                //Now invoke the method.
                bool retVal = (bool)target.Invoke(null, parameters);
            }
            catch (Exception ex)
            {
                // When we print informations from a SecurityException extra information can be printed if we are 
                //calling it with a full-trust stack.
                (new PermissionSet(PermissionState.Unrestricted)).Assert();
                Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());
                CodeAccessPermission.RevertAssert();
                Console.ReadLine();
            }
        }
    }
    

    【讨论】:

    • 这太棒了 - 但在 .NET Core 中该怎么办?
    【解决方案2】:

    如果我正确理解您的观点,我想这就是您所需要的。

    System.Security.PermissionSet ps = 
        new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);
    ps.AddPermission(new System.Security.Permissions.FileIOPermission(System.Security.Permissions.FileIOPermissionAccess.NoAccess, "C:\\"));
    System.Security.Policy.PolicyLevel pl = System.Security.Policy.PolicyLevel.CreateAppDomainLevel();
    pl.RootCodeGroup.PolicyStatement = new System.Security.Policy.PolicyStatement(ps);
    AppDomain.CurrentDomain.SetAppDomainPolicy(pl);
    System.Reflection.Assembly myPluginAssembly = AppDomain.CurrentDomain.Load("MyPluginAssembly");
    

    你的意思更准确吗?

    请注意,您可以提供一个字符串数组,其中包含您不希望插件访问的路径。您可以在初始化 FileIOPermission 类的新实例时提供 if。

    如果这有帮助,请告诉我。 :-)

    【讨论】:

    • 这似乎正是我所追求的,我得到了给定的程序集名称或代码库无效。 (来自 HRESULT 的异常:0x80131047)现在但我还没有时间进一步研究它(我做错了什么)。我明天有更多时间,我会告诉你
    • 那么,最后,这就是您要找的吗?我猜,因为你似乎已经检查过了。 :-)
    • @EKS 您必须从同一文件夹或该文件夹的子文件夹之一加载。
    【解决方案3】:

    如果您使用插件,您可能知道代理。

    通过代理加载程序集时,如果我没记错的话,您可以通过 LoadAssembly() 方法为这个特定程序集指定安全策略级别。换句话说,这是通过反射完成的。

    我知道我的回答不是很详细,但我希望它能让您了解在哪里寻找解决方案。我会注意寻找有关该主题的更多详细信息,以便我可以提供更好的帮助。 =)

    希望您在完成后分享您的发现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      相关资源
      最近更新 更多