订阅域事件时C# AppDomain沙箱安全异常
我正在编写一个插件系统来在我的服务器应用程序(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 )
{
}
}
}
运行此代码后,我在域上遇到以下异常。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 提供完整反射能力的情况下解决它。请问有人有建议或解释吗?
I'm writing a plugin system to run client-provided untrusted code in my server application (C#, .NET 4.0). In order to do this, i'm running each plugin in a new sandboxed AppDomain.
However, I'm stuck on a security exception that I don't really understand the reason for. I have made a streamlined console application sample to illustrate the problem:
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 )
{
}
}
}
Upon running this code, I'm getting the following exception on the domain.AssemblyLoad line:
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>
My best guess is that there's some event-subscription code under the hood executing in the new sandboxed AppDomain without the required security permissions, but I don't know how to work around it without giving full reflection-capacity to the sandboxed AppDomain. Does anyone have a suggestion or explanation, please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简短回答:
用于向事件 AppDomain.AssemblyLoad 添加处理程序的隐藏方法 - 由 SecurityCriticalAttribute 标记。检查 ILASM:
为了执行此方法,您必须在(沙箱域的)FullTrust 模式下执行它。故事结束。
长答案:
您正在处理跨域通信。意味着您的事件处理程序将在沙箱域的空间中执行,然后使用注册到您的父域的远程处理。您提供的代码需要反射权限,无论您在该方法中使用什么事件 - 安全性是否关键。
因此,如果您希望沙箱域与父域进行安全通信,您应该使用经典的 .NET Remoting 方法,此代码不需要任何额外的权限,并允许通知父域有关沙箱域上发生的事件:
Short answer:
Hidden method for adding handler to event AppDomain.AssemblyLoad - marked by SecurityCriticalAttribute. Check ILASM:
In order to execute this method you MUST execute it in FullTrust mode (of your sandbox domain). End of story.
Long answer:
You are dealing with Cross Domain communication. Means your event handler will be executed in the space of Sandbox domain, and then using remoting enrolled to you parent domain. The code you provided requires Reflection permission, it does not matter what event you use in that approach - security critical or not.
So if you want your sandbox domain to do safe communication with your parent domain you should use classic .NET Remoting approach, this code will not require any additional permissions and allow to notify parent domain about events happened on sandbox domain: