4

我正在尝试创建一个沙盒 AppDomain 来加载扩展/插件。我有一个 MarshalByRefObject,它在 appdomain 内实例化以加载 dll。我在尝试加载 dll 时遇到 SecurityExceptions,我不知道如何绕过它们,同时仍然限制第三方代码可以做什么。我所有的项目都是.net 4。

InDomainLoader 类位于完全受信任的域中,该方法标记为 SecuritySafeCritical。从我读过的所有内容来看,我认为这应该有效。

这是我的 Loader 类,它创建 AppDomain 并跳转到它:

public class Loader
{
    public void Load(string dll, string typeName)
    {
        Log.PrintSecurity();

        // Create new AppDomain
        var setup = AppDomain.CurrentDomain.SetupInformation;
        var permissions = new PermissionSet(null);
        permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        var strongname = typeof(InDomainLoader).Assembly.Evidence.GetHostEvidence<StrongName>();
        var strongname2 = typeof(IPlugin).Assembly.Evidence.GetHostEvidence<StrongName>();
        AppDomain domain = AppDomain.CreateDomain("plugin", null, setup, permissions, strongname, strongname2);

        // Create instance
        var loader = (InDomainLoader)domain.CreateInstanceAndUnwrap(
            typeof (InDomainLoader).Assembly.FullName, typeof (InDomainLoader).FullName);

        // Jump into domain
        loader.Load(dll, typeName);
    }
}

这是在域中运行的引导加载程序:

public class InDomainLoader : MarshalByRefObject
{
    [SecuritySafeCritical]
    public void Load(string dll, string typeName)
    {
        Log.PrintSecurity();

        var assembly = Assembly.LoadFrom(dll);  // <!-- SecurityException!
        var pluginType = assembly.GetType(typeName);

        var demoRepository = new DemoRepository();
        var plugin = (IPlugin)Activator.CreateInstance(pluginType, demoRepository);
        Console.WriteLine(plugin.Run());
    }
}

一些日志记录语句告诉我程序集IsFullyTrusted是真的,并且该方法具有两者IsSecurityCriticalIsSecuritySafeCritical设置为真,IsSecurityTransparent是假的。

我将整个项目压缩到http://davidhogue.com/files/PluginLoader.zip,以防万一这更容易。

如果有人有任何想法,我将不胜感激。我似乎在这里陷入了死胡同。

4

1 回答 1

6

首先,您可能不应该将该函数标记为 SecuritySafeCritical,因为这意味着不受信任的调用者可以呼叫您,而您可能并不真正想要(这不是一个主要问题)。

至于您的问题,问题是默认情况下您仍然没有使用任何特殊权限运行,执行程序集加载的正常简单方法是创建自己的 AppDomainSetup 并将其 ApplicationBase 指向某种插件目录(即一般来说,这不是一个坏主意),然后您可以使用普通的 Assembly.Load("AssemblyName") 从基础加载。但是,如果您必须加载任意文件,则需要为插件 dll(完整路径)声明 FileIOPermission,即

private Assembly LoadAssemblyFromFile(string file)
{
    FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.AllAccess, file);
    perm.Assert();

    return Assembly.LoadFile(file);
}
于 2010-09-13T23:53:58.733 回答