Ограничить доступ плагина к файловой системе и сети через домен приложения - PullRequest
10 голосов
/ 31 августа 2009

Я недавно спросил, как ограничить доступ плагинов (я хочу запретить им запись на диск или в сеть), и мне сказали использовать AppDomain . Я искал, пытался и не смог, как заставить это работать.

Может ли кто-нибудь предоставить некоторую информацию, чтобы я мог начать, просто создайте домен AppDomain, который не разрешает запись в файл или сеть.

Ответы [ 3 ]

16 голосов
/ 11 апреля 2011

Для .net framework 4.0, следуйте следующему коду из этой статьи MSDN.

В следующем примере реализована процедура из предыдущего раздела. В этом примере проект с именем Sandboxer в решении Visual Studio также содержит проект с именем 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;
        }
    }
}

В следующем примере показан код приложения 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();
        }
    }
}
6 голосов
/ 01 сентября 2009

Полагаю, это то, что вам нужно, если я правильно понимаю вашу точку зрения.

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.

Дайте мне знать, если это поможет. : -)

0 голосов
/ 31 августа 2009

Если вы используете плагины, возможно, вы знаете о прокси.

При загрузке вашей сборки через прокси вы можете указать уровень политики безопасности для этой конкретной сборки с помощью метода LoadAssembly () или около того, если я правильно помню. Другими словами, это делается с помощью рефлексии.

Я знаю, что мой ответ не настолько подробен, но я надеюсь, что он даст вам представление о том, где искать ваше решение. Я постараюсь найти дополнительную информацию по этому вопросу, чтобы я мог оказать вам лучшую помощь. =)

Надеюсь, что вы поделитесь своими результатами, когда вы это сделали.

...