我想从运行时创建的程序集中调用方法。它是部分受信任的代码,因此我想为它创建一个沙箱应用程序域。
我使用Roslyn创建程序集,结果是byte[]
。我可以加载它并在默认的Appdomain
中从它调用,它工作正常。问题是(我猜)沙箱。
我使用this tutorial。
创建沙箱Appdomain
:
private AppDomain createAppdomain(string location)
{
AppDomain currentAppdomain = AppDomain.CurrentDomain;
// Create the permission set to be granted to the untrusted application
Evidence ev = new Evidence();
ev.AddHostEvidence(new Zone(SecurityZone.Internet));
PermissionSet internetPS = SecurityManager.GetStandardSandbox(ev);
var platform = Assembly.GetExecutingAssembly();
internetPS.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, Path.GetDirectoryName(platform.Location)));
// Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code
// .NET Framework assemblies such as mscorlib and System.dll do not have to be added to the full-trust list
// because they are loaded as fully trusted from the global assembly cache.
StrongName[] fullTrustAssembly = new StrongName[1];
fullTrustAssembly[0] = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();
// Initialize the AppDomainSetup parameter of the CreateDomain method
// The ApplicationBase property is an important setting,
// and should be different from the ApplicationBase property for the AppDomain of the hosting application.
// If the ApplicationBase settings are the same,
// the partial-trust application can get the hosting application to load (as fully trusted) an exception it defines, thus exploiting it.
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = Path.GetFullPath(location);
// Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain
// http://msdn.microsoft.com/en-us/library/ms130766(v=vs.110).aspx
AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, internetPS, fullTrustAssembly);
return newDomain;
}
创建沙箱(沙箱类型为MarshalByRefObject
):
string physicalPath = HttpContext.Current.Request.PhysicalApplicationPath + @"App_Data\";
AppDomain Sandbox = createAppdomain(physicalPath);
// http://msdn.microsoft.com/en-us/library/dd413384(v=vs.110).aspx
ObjectHandle handle = Activator.CreateInstanceFrom(
Sandbox,
typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
typeof(Sandboxer).FullName,
true,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance,
null,
// byte[] rawAssembly
new object[] { rawAssembly },
null,
null);
Sandboxer newDomainInstance = (Sandboxer)handle.Unwrap();
string s = newDomainInstance.callMethod();
加载Assembly
,调用方法:
private string callMethod()
{
// No Exception thrown yet, but some problems with the Evidence:
// Evidence 'asm.Evidence' threw an exception of type 'System.Security.SecurityException' System.Security.Policy.Evidence {System.Security.SecurityException}
//"Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed."
Assembly asm = Assembly.Load(rawAssembly);
Type MyClass = asm.GetType(myClassName);
// In this line I get the Exception:
// System.Security.SecurityException
// "Request failed."
object obj = Activator.CreateInstance(MyClass);
MethodInfo mi = MyClass.GetMethod(myMethodName);
mi.Invoke(obj, null);
// some code
return s;
}
堆栈跟踪:
"at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type) ..."
我错过了什么? (抱歉我的英文。)
编辑: 试图将此行添加到类中以授予完全权限:
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
此后object obj = Activator.CreateInstance(MyClass);
工作正常。我需要沙盒,所以这不是解决方案。
答案 0 :(得分:3)
我遇到了同样的问题,并且把头撞了一个小时。
因为我在另一个例子中有相同的代码运行良好!
所以我开始移除东西,直到我发现唯一的区别在于装载程序的方式:Assembly.LoadFrom
工作正常。总是Assembly.Load(byte[])
给了我一个安全例外。
该异常表明我的沙箱DLL是问题的根源,但没有帮助。因为它在MSDN文档中只是一句话:
使用此方法加载的程序集的信任级别与调用程序集的信任级别相同。要从具有应用程序域的信任级别的字节数组加载程序集,请使用Load(Byte [],Byte [],SecurityContextSource)方法重载
糟糕!我认为在具有非常有限权限的appdomain中加载具有&#34;完全信任&#34;的程序集,而不是在完全受信任的列表中,使得CLR不满意。第一行从加载的程序集执行 - &gt;砰! (这就是我断言异常令人困惑的原因:它提到&#34;错误&#34; DLL作为异常源)
所以我将Load(byte[])
替换为Load(Byte[], null, SecurityContextSource.CurrentAppDomain)
,现在它就像LoadFrom
答案 1 :(得分:1)
您的问题是您加载的Sandboxer程序集,而使用不受信任的堆栈调用完全受信任的程序集。因此,您在激活的某个位置获得安全性异常(不是100%确定为什么基于您的代码)。解决方案正如您所发现的那样,将断言添加到函数中。这将允许此函数以完全信任的方式执行(断言将阻止堆栈遍历),但加载的程序集部分受信任,因此仍将进行沙盒化。
如果这样做,您需要确保沙盒代码无法与该方法交互,因此可能会滥用它。您可以通过标记SecurityCritical函数来执行此操作,以便只有完全受信任的代码才能与该函数进行交互。