2011-10-16 12 views
7

Sto scrivendo un sistema di plugin per eseguire codice non attendibile fornito dal client nella mia applicazione server (C#, .NET 4.0). Per fare questo, eseguo ogni plugin in un nuovo AppDomain sandbox.C# AppDomain Eccezione di sicurezza sandbox quando si sottoscrive eventi di dominio

Tuttavia, sono bloccato su un'eccezione di sicurezza che non capisco davvero il motivo. Ho fatto un esempio un'applicazione console semplificato per illustrare il problema:

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) 
     { 

     } 
    } 
} 

Al momento dell'esecuzione di questo codice, sto ottenendo la seguente eccezione sulla linea 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> 

La mia ipotesi migliore è che c'è un codice di sottoscrizione di eventi sotto il cofano che si sta eseguendo nel nuovo AppDomain sandbox senza le autorizzazioni di sicurezza necessarie, ma non so come aggirarlo senza dare piena capacità di riflessione all'appDomain in modalità sandbox. Qualcuno ha un suggerimento o una spiegazione, per favore?

risposta

4

Risposta breve:

metodo nascosti per l'aggiunta di gestore di eventi AppDomain.AssemblyLoad - segnata da SecurityCriticalAttribute. Controllare 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 

Per eseguire questo metodo è necessario eseguire in modalità FullTrust (del dominio sandbox). Fine della storia.

Risposta lunga:

Avete a che fare con la comunicazione tra domini. Significa che il gestore di eventi verrà eseguito nello spazio del dominio Sandbox e quindi utilizzando i servizi remoti registrati al dominio padre. Il codice che hai fornito richiede il permesso di Reflection, non importa quale evento usi in quell'approccio: sicurezza critica o meno.

Quindi, se si desidera che il proprio dominio sandbox esegua comunicazioni sicure con il dominio padre, è necessario utilizzare l'approccio classico .NET Remoting, questo codice non richiederà autorizzazioni aggiuntive e consentirà di notificare il dominio padre sugli eventi accaduti sul dominio sandbox:

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(); 
     } 


    } 
} 
Problemi correlati