[英]C# AppDomain sandbox security exception when subscribing to domain events
我正在編寫一個插件系統來在我的服務器應用程序(C#,.NET 4.0)中運行客戶端提供的不受信任的代碼。 為了做到這一點,我在一個新的沙盒AppDomain中運行每個插件。
但是,我堅持一個安全例外,我真的不明白它的原因。 我已經制作了一個簡化的控制台應用程序示例來說明問題:
namespace SandboxTest
{
class Program
{
static void Main( string[] args )
{
Sandbox sandbox = new Sandbox();
Console.ReadLine();
}
}
class Sandbox
{
AppDomain domain;
public Sandbox()
{
PermissionSet ps = new PermissionSet( PermissionState.None );
ps.AddPermission( new SecurityPermission( SecurityPermissionFlag.Execution ) );
try
{
domain = AppDomain.CreateDomain( "Sandbox", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation, ps );
domain.AssemblyLoad += new AssemblyLoadEventHandler( domain_AssemblyLoad );
domain.AssemblyResolve += new ResolveEventHandler( domain_AssemblyResolve );
}
catch( Exception e )
{
Trace.WriteLine( e.ToString() );
throw e;
}
}
static Assembly domain_AssemblyResolve( object sender, ResolveEventArgs args )
{
return null;
}
static void domain_AssemblyLoad( object sender, AssemblyLoadEventArgs args )
{
}
}
}
運行此代碼后,我在domain.AssemblyLoad行上收到以下異常:
A first chance exception of type 'System.Security.SecurityException' occurred in SandboxTest.exe
'SandboxTest.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(RuntimeAssembly asm, PermissionSet granted, PermissionSet refused, RuntimeMethodHandleInternal rmh, SecurityAction action, Object demand, IPermission permThatFailed)
at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Object assemblyOrString, PermissionSet granted, PermissionSet refused, RuntimeMethodHandleInternal rmh, SecurityAction action, Object demand, IPermission permThatFailed)
at System.Security.CodeAccessSecurityEngine.CheckHelper(PermissionSet grantedSet, PermissionSet refusedSet, CodeAccessPermission demand, PermissionToken permToken, RuntimeMethodHandleInternal rmh, Object assemblyOrString, SecurityAction action, Boolean throwException)
at System.Security.CodeAccessSecurityEngine.CheckHelper(CompressedStack cs, PermissionSet grantedSet, PermissionSet refusedSet, CodeAccessPermission demand, PermissionToken permToken, RuntimeMethodHandleInternal rmh, RuntimeAssembly asm, SecurityAction action)
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
at System.Security.CodeAccessPermission.Demand()
at System.DelegateSerializationHolder.GetDelegateSerializationInfo(SerializationInfo info, Type delegateType, Object target, MethodInfo method, Int32 targetIndex)
at System.MulticastDelegate.GetObjectData(SerializationInfo info, StreamingContext context)
at System.Runtime.Serialization.ObjectCloneHelper.GetObjectData(Object serObj, String& typeName, String& assemName, String[]& fieldNames, Object[]& fieldValues)
at System.AppDomain.add_AssemblyLoad(AssemblyLoadEventHandler value)
at SandboxTest.Sandbox..ctor() in C:\Dev\Projects\Botfield\SandboxTest\Program.cs:line 36
The action that failed was:
Demand
The type of the first permission that failed was:
System.Security.Permissions.ReflectionPermission
The first permission that failed was:
<IPermission class="System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Flags="MemberAccess"/>
The demand was for:
<IPermission class="System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Flags="MemberAccess"/>
The granted set of the failing assembly was:
<PermissionSet class="System.Security.PermissionSet"
version="1">
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Flags="Execution"/>
</PermissionSet>
我最好的猜測是,在沒有所需安全權限的情況下,在新的沙盒AppDomain中執行了一些事件訂閱代碼,但我不知道如何在不給沙盒AppDomain提供完全反射能力的情況下解決它。 有人有建議或解釋嗎?
簡短回答 :
用於向事件AppDomain.AssemblyLoad添加處理程序的隱藏方法 - 由SecurityCriticalAttribute標記。 檢查ILASM:
.method public hidebysig newslot specialname virtual final
instance void add_AssemblyLoad(class System.AssemblyLoadEventHandler 'value') cil managed
{
.custom instance void System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 )
// Code size 0 (0x0)
} // end of method AppDomain::add_AssemblyLoad
為了執行此方法,您必須在FullTrust模式(沙箱域)中執行它。 故事結局。
答案很長 :
您正在處理跨域通信。 表示您的事件處理程序將在Sandbox域的空間中執行,然后使用注冊到您的父域的遠程處理。 您提供的代碼需要反射權限,您在該方法中使用的事件無關緊要 - 安全性是否至關重要。
因此,如果您希望沙盒域與父域進行安全通信,則應使用經典的.NET Remoting方法,此代碼不需要任何其他權限,並允許通知父域有關沙箱域上發生的事件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Security.Permissions;
using System.Diagnostics;
using System.Reflection;
namespace SandboxTest
{
class Program
{
static void Main(string[] args)
{
Sandbox sandbox = new Sandbox();
Console.ReadLine();
}
}
class Sandbox
{
AppDomain domain;
public Sandbox()
{
PermissionSet ps = new PermissionSet(PermissionState.None);
ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
try
{
domain = AppDomain.CreateDomain("Sandbox", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation, ps);
var tp = typeof(MyInit);
var obj = (MyInit)domain.CreateInstanceAndUnwrap(tp.Assembly.FullName, tp.FullName);
var myCallBack = new MyCallBack();
myCallBack.Generated += new EventHandler(myCallBack_Generated);
obj.Subscribe(myCallBack);
obj.GenerateCallBackEvent();
}
catch (Exception e)
{
Trace.WriteLine(e.ToString());
throw e;
}
}
void myCallBack_Generated(object sender, EventArgs e)
{
//Executed in parent domain
}
}
public class MyCallBack:MarshalByRefObject
{
public void GenerateEvent()
{
//Executed in parent domain, but triggered by sandbox domain
if (Generated != null) Generated(this, null);
}
//for parent domain only
public event EventHandler Generated;
}
public class MyInit:MarshalByRefObject
{
public MyInit()
{
}
MyCallBack callback;
public void Subscribe(MyCallBack callback)
{
//executed on sandbox domain
this.callback = callback;
}
public void GenerateCallBackEvent()
{
//executed on sandbox domain
callback.GenerateEvent();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.