我在尝试使用如下定义的受限权限创建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;
}
}
答案 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);