Мое приложение должно быть доступно для сценариев для пользователей на C#, но скрипт пользователя должен работать в ограниченном AppDomain, чтобы предотвратить случайное причинение вреда сценариям, но я не могу получить его до работа, и поскольку мое понимание AppDomains, к сожалению, ограничено, я не могу сказать, почему.Запуск скомпилированного сценария C# в песочнице AppDomain
Решение, на котором я сейчас пытаюсь, основывается на этом ответе https://stackoverflow.com/a/5998886/276070.
Это модель моей ситуации (все, кроме Script.cs, проживающих в сильно названной сборке). Извините за стеной кода, я не мог конденсировать проблему дальше.
class Program
{
static void Main(string[] args)
{
// Compile the script
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters()
{
GenerateExecutable = false,
OutputAssembly = System.IO.Path.GetTempFileName() + ".dll",
};
parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location);
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, "Script.cs");
// ... here error checks happen ....//
var sandbox = Sandbox.Create();
var script = (IExecutable)sandbox.CreateInstance(results.PathToAssembly, "Script");
if(script != null)
script.Execute();
}
}
public interface IExecutable
{
void Execute();
}
Песочница класс:
public class Sandbox : MarshalByRefObject
{
const string BaseDirectory = "Untrusted";
const string DomainName = "Sandbox";
public static Sandbox Create()
{
var setup = new AppDomainSetup()
{
ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory),
ApplicationName = DomainName,
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions,
typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>());
return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
}
public object CreateInstance(string assemblyPath, string typeName)
{
new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
var assembly = Assembly.LoadFile(assemblyPath);
CodeAccessPermission.RevertAssert();
Type type = assembly.GetType(typeName); // ****** I get null here
if (type == null)
return null;
return Activator.CreateInstance(type);
}
}
Загруженный Сценарий:
using System;
public class Script : IExecutable
{
public void Execute()
{
Console.WriteLine("Boo");
}
}
В CreateInstance
из SandBox
, я всегда получаю null
на отмеченной линии. Я пробовал различные формы присвоения имени, включая чтение имени типа (или фамилии с наивысшим названием) от results.CompiledAssembly
с использованием отражения. Что я здесь делаю неправильно?
Если я Не ошибиться при компиляции сборки с помощью CodeDom, она загружается в текущий AppDomain. Вы должны скомпилировать в дочернем AppDomain и иметь производный класс MarshalByRefObject, который реализует IExecutable. Это можно сохранить в другой сборке, на которую ссылаются как приложение, так и динамически скомпилированная сборка. Затем используйте это как базовый класс для своих скриптов. Таким образом, никакой тип не просачивается. Кстати, класс Script должен либо быть выведенным или сериализуемым MarshalByRefObject, чтобы иметь возможность пересекать AppDomains. –
Спасибо за ввод. У меня создалось впечатление, что он загрузился только в текущий AppDomain, если установлен GenerateInMemory или используется свойство CompilerResults.CompiledAssembly. Требуется больше исследований. =) Компиляция внутри нового AppDomain создает исключение SecurityException для CodeDomProvider.CreateProvider, если я не использую PermissionState.Неограниченный, что нежелательно. Я еще не выяснил, какие разрешения действительно нужны. – Jens
Удачи вам в квете разрешений. Это головная боль. Кстати, вы можете скомпилировать дочерний AppDomain с полными разрешениями, а затем подготовить песочницу в другом. –