需求是:<permissionset class =“System.Security.PermissionSet”version =“1”unrestricted =“true”> </permissionset>

时间:2014-01-06 18:50:42

标签: c# sandbox appdomain code-access-security

我在尝试使用如下定义的受限权限创建AppDomain时收到System.Security.SecurityException The demand was for: <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true"/>

var permissionSet = new PermissionSet(PermissionState.None);
    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, System.Reflection.Assembly.GetExecutingAssembly().Location));
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));

此错误消息告诉我它将接受不低于无限制/完全信任的环境,但我不明白为什么要求或如何修复它。

我只在新的受限AppDomain中创建了Stub的一个实例:

public interface IHostStub // Implemented by a MarshalByRefObject object in the primary AppDomain
{
    void Ping();
    void SayTime(DateTimeOffset time);
}

// In the restricted AppDomain
class Stub : MarshalByRefObject
{
    public event EventHandler OnQuit;

    public void RequestTime(IHostStub host)
    {    
        host.SayTime(DateTimeOffset.Now);
    }

    public void Quit(IHostStub host)
    {
        if (this.OnQuit != null) 
            this.OnQuit(this, new EventArgs());
    }
}

您能否向我解释此错误消息?也许我误解了Unrestricted的含义。但是将其设置为Unrestricted似乎可以让app域免费统治(正如我预期的那样),无论我添加或不添加任何权限。

谢谢!

====

为了回应@Nicole并在我完成这项工作时添加一些发现,下面是两个代码示例。这是一个棘手的场景 - 沙盒插件 - 需要太多代码来显示所有内容。第一个代码示例演示了异常。它有一个明显的解决方案,但它没有考虑整个场景。

class Program
{
    static void Main(string[] args)
    {
        var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

        var permissionSet = new PermissionSet(PermissionState.None);
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, currentAssembly.Location));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
        permissionSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));

        var appDomain = AppDomain.CreateDomain(
            "Sandboxed",
            null,
            new AppDomainSetup
            {
                ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
            },
            permissionSet,
            Assembly.GetExecutingAssembly().Evidence.GetHostEvidence<StrongName>());

        try
        {
            var stub = (Stub)appDomain.CreateInstanceFromAndUnwrap(
                currentAssembly.Location,
                typeof(Stub).FullName);
        }
        catch (SecurityException ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }
}

// In the restricted AppDomain
class Stub : MarshalByRefObject
{
}

在该示例中,ApplicationBase与主AppDomain相同。此外,程序集本身也列为AppDomain的FullTrust程序集。琐碎的解决方法是删除那个完全信任的参数。

在下一个示例中,为了防止插件加载主机程序集,ApplicationBase设置为甚至不需要存在的随机路径(与PermissionState.Unrestricted一起使用,如果目录存在,则会出现相同的错误) 。 AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;需要完全信任AFAIK,因此我必须列出具有完全信任的程序集(我认为应该覆盖针对该可信程序集的AppDomain上设置的任何限制,但不能覆盖其可能加载的其他限制) - 此程序集可以只是“加载程序”,插件将是另一个应该强制执行受限权限的程序集的一部分。我必须自定义AssemblyResolve,因为该目录不存在(或为空),因为我想控制加载其他程序集(例如,来自byte[])。

class Program
{
    static void Main(string[] args)
    {
        var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

        var permissionSet = new PermissionSet(PermissionState.None);
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, currentAssembly.Location));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
        permissionSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));

        string path;
        do
        {
            path = Path.GetTempPath() + Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
        } while (Directory.Exists(path));

        var appDomain = AppDomain.CreateDomain(
            "Sandboxed",
            null,
            new AppDomainSetup
            {
                ApplicationBase = path
            },
            permissionSet,
            Assembly.GetExecutingAssembly().Evidence.GetHostEvidence<StrongName>());

        try
        {
            var stub = (Stub)appDomain.CreateInstanceFromAndUnwrap(
                currentAssembly.Location,
                typeof(Stub).FullName);
        }
        catch (SecurityException ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }
}

class Stub : MarshalByRefObject
{
    static Stub()
    {
        AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
    }

    public static Assembly AssemblyResolve(object sender, ResolveEventArgs e)
    {
        if (e.Name == Assembly.GetExecutingAssembly().FullName)
            return Assembly.GetExecutingAssembly();
        else
            Console.WriteLine("Unable to load {0}", e.Name);

        return null;
    }
}

1 个答案:

答案 0 :(得分:3)

尝试通过Activator.CreateInstanceFrom而不是AppDomain.CreateInstanceFromAndUnwrap创建存根句柄。权限验证有所不同,使用Activator方法还应允许您避免将额外权限(除SecurityPermission\Execution之外)添加到沙盒应用域。 e.g

var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

var permissionSet = new PermissionSet(PermissionState.None);
permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

var appDomain = AppDomain.CreateDomain(
    "Sandboxed",
    null,
    new AppDomainSetup { ApplicationBase = CreateFakePath() },
    permissionSet,
    currentAssembly.Evidence.GetHostEvidence<StrongName>());

var stub = (Stub)Activator.CreateInstanceFrom(appDomain, currentAssembly.Location, typeof(Stub).FullName).Unwrap();

var hostStub = new HostStub();
stub.RequestTime(hostStub);