Выполнение ненадежного кода - PullRequest
2 голосов
/ 13 марта 2010

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

Я рассмотрел три варианта.

  1. Использование System.AddIn. Сначала я попробовал эту альтернативу, потому что она выглядела очень мощно, но я действительно разочарован необходимостью изменять один и тот же код семь раз в семи разных проектах каждый раз, когда я хочу что-то изменить. Кроме того, существует огромное количество проблем, которые нужно решить даже для простого приложения Hello World.

  2. Использование System.Activator.CreateInstance (assemblyName, typeName). Это то, что я использовал в предыдущей версии приложения. Я больше никогда не смогу его использовать, потому что он не позволяет ограничивать разрешения.

  3. Использование System.Activator.CreateInstance (домен AppDomain, [...]). Это то, что я сейчас пытаюсь реализовать, но, похоже, единственный способ сделать это - пройти через ObjectHandle, который требует сериализации для каждого используемого класса. Хотя подключаемые модули содержат пользовательские элементы управления WPF, которые нельзя сериализировать.

Так есть ли способ создания плагинов, содержащих UserControls или другие несериализуемые объекты, и запуск этих плагинов с помощью специального PermissionSet?

1 Ответ

1 голос
/ 13 марта 2010

Одна вещь, которую вы могли бы сделать, - установить текущий уровень политики 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:)

...