C# 通过appdomain限制插件对文件系统和网络的访问

C# 通过appdomain限制插件对文件系统和网络的访问,c#,appdomain,C#,Appdomain,不久前我问过如何限制插件访问(我想阻止它们写入磁盘或网络),有人告诉我使用。我已经搜索并尝试了如何让它工作,但失败了 谁能提供一些信息让我开始,简单地说,创建一个不允许写入文件或网络的AppDomain。如果您使用插件,您可能知道代理 通过代理加载程序集时,如果我没记错的话,可以通过LoadAssembly()方法或其他方法指定此特定程序集的安全策略级别。换句话说,这是通过反射完成的 我知道我的答案没有那么详细,但我希望它能让你知道在哪里可以找到解决方案。我将密切注意这个问题的进一步细节,以便能

不久前我问过如何限制插件访问(我想阻止它们写入磁盘或网络),有人告诉我使用。我已经搜索并尝试了如何让它工作,但失败了


谁能提供一些信息让我开始,简单地说,创建一个不允许写入文件或网络的AppDomain。

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

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

我知道我的答案没有那么详细,但我希望它能让你知道在哪里可以找到解决方案。我将密切注意这个问题的进一步细节,以便能提供更好的帮助


希望你完成后能分享你的发现。

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

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


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

对于.net framework 4.0,请遵循MSDN文章中的以下代码

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

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;
        }
    }
}
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();
        }
    }
}
下面的示例显示了执行不受信任代码的沙盒应用程序代码

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;
        }
    }
}
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();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.IO;
使用系统安全;
使用系统、安全、策略;
使用System.Security.Permissions;
运用系统反思;
使用System.Runtime.Remoting;
//沙盒类需要从MarshallByRefObject派生,以便我们可以在另一个环境中创建它
//AppDomain并从默认AppDomain引用它。
类沙盒:MarshalByRefObject
{
常量字符串pathToUntrusted=@“.\..\..\UntrustedCode\bin\Debug”;
常量字符串untrustedAssembly=“UntrustedCode”;
常量字符串untrustdclass=“untrustdcode.untrustdclass”;
常量字符串入口点=“IsFibonacci”;
私有静态对象[]参数={45};
静态void Main()
{
//设置AppDomainSetup。将ApplicationBase设置为文件夹非常重要
//而不是沙盒所在的沙盒。
AppDomainSetup adSetup=新建AppDomainSetup();
adSetup.ApplicationBase=Path.GetFullPath(pathToUntrusted);
//正在设置AppDomain的权限。我们授予执行和访问的权限
//读取/发现加载不受信任代码的位置。
PermissionSet permSet=新的PermissionSet(PermissionState.None);
AddPermission(新的SecurityPermission(SecurityPermissionFlag.Execution));
//我们需要沙盒程序集的强名称,以便将其添加到完整信任列表中。
StrongName fullTrustAssembly=typeof(沙盒).Assembly.Evidence.GetHostEvidence();
//现在我们有了创建AppDomain所需的一切,让我们来创建它。
AppDomain newDomain=AppDomain.CreateDomain(“沙盒”,null,adSetup,permSet,fullTrustAssembly);
//使用CreateInstanceFrom将沙盒类的实例加载到
//新建AppDomain。
ObjectHandle=Activator.CreateInstanceFrom(
newDomain,typeof(沙盒).Assembly.ManifestModule.FullyQualifiedName,
类型(沙盒)。全名
);
//将新域实例展开为此域中的引用,并使用它执行
//不受信任的代码。
沙盒newDomainInstance=(沙盒)handle.Unwrap();
ExecuteUntrustedCode(不可信组件、不可信类、入口点、参数);
}
public void executeIntrustedCode(字符串程序集名称、字符串类型名称、字符串入口点、对象[]参数)
{
//为新程序集中的方法加载MethodInfo。这可能是您知道的方法,或者
//您可以使用Assembly.EntryPoint访问可执行文件中的主函数。
MethodInfo目标=Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);
尝试
{
//现在调用该方法。
bool retVal=(bool)target.Invoke(null,参数);
}
捕获(例外情况除外)
{
//当我们从SecurityException打印信息时,如果需要,可以打印额外的信息
//使用完全信任堆栈调用它。
(新PermissionSet(PermissionState.Unrestricted)).Assert();
WriteLine(“捕获到SecurityException:\n{0}”,例如ToString());
CodeAccessPermission.RevertAssert();
Console.ReadLine();
}
}
}

这似乎正是我所追求的,我得到的给定程序集名称或代码库无效。(HRESULT的例外:0x80131047)现在,但我还没有时间进一步研究它(我可能做错了什么)。我明天会有更多的时间让你知道最后,这就是你想要的吗?我猜,因为你似乎已经检查过了。:-)@EKS必须从同一个文件夹或该文件夹的子文件夹之一加载。这太棒了-但是在.NETCore中该怎么做呢?