Condividi tramite


Procedura dettagliata: creazione di codice in scenari di attendibilità parziale

Reflection emit utilizza le stesse API impostate in attendibilità totale o parziale, ma alcune funzionalità richiedono autorizzazioni speciali per il codice parzialmente attendibile. Inoltre, reflection emit presenta una funzionalità, metodi dinamici ospitati anonimamente, progettati per essere utilizzati in scenari di attendibilità parziale e dagli assembly SecurityTransparent.

NotaNota

Prima di .NET Framework versione 3.5, l'emissione di codice richiedeva ReflectionPermission con il flag ReflectionPermissionFlag.ReflectionEmit.Questa autorizzazione è inclusa per impostazione predefinita nei set di autorizzazioni denominati FullTrust e Intranet, ma non nel set di autorizzazioni Internet.Di conseguenza, una libreria può essere utilizzata da un contesto di attendibilità parziale solo se dispone dell'attributo SecurityCriticalAttribute ed esegue un metodo Assert per ReflectionEmit. Tali librerie richiedono un'accurata revisione della sicurezza perché eventuali errori nel codice potrebbero comportare problemi di sicurezza..NET Framework 3.5 consente l'emissione di codice in scenari di attendibilità parziale senza alcuna richiesta di sicurezza, in quanto la generazione di codice non è, per sua natura, un'operazione privilegiata.In altre parole, il codice generato dispone delle stesse autorizzazioni dell'assembly di emissione.Questo consente alle librerie che generano il codice di essere security transparent ed elimina la necessità di asserire ReflectionEmit, in modo tale che la scrittura di una libreria protetta non richieda una revisione della sicurezza così approfondita.

In questa procedura dettagliata vengono illustrate le seguenti attività:

  • Configurazione di una sandbox semplice per il test di codice parzialmente attendibile.

    Nota importanteImportante

    Si tratta di un modo semplice per sperimentare il codice in un contesto di attendibilità parziale.Per eseguire codice realmente proveniente da percorsi non attendibili, vedere Procedura: eseguire codice parzialmente attendibile in un oggetto sandbox.

  • Esecuzione di codice nei domini applicazione parzialmente attendibili.

  • Utilizzo di metodi dinamici ospitati anonimamente per generare ed eseguire codice in attendibilità parziale.

Per ulteriori informazioni sulla generazione di codice in scenari di attendibilità parziale, vedere Problemi di sicurezza nella reflection emit.

Per un elenco completo del codice illustrato in queste procedure, vedere la sezione Esempio alla fine di questa procedura dettagliata.

Impostazione di percorsi parzialmente attendibili

Nelle due procedure descritte di seguito viene illustrato come configurare percorsi dai quali sia possibile eseguire il test di codice con attendibilità parziale.

  • Nella prima procedura viene descritto come creare un dominio applicazione sandbox nel quale vengono concesse al codice autorizzazioni Internet.

  • Nella seconda procedura viene descritto come aggiungere ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess a un dominio applicazione parzialmente attendibile per consentire l'accesso ai dati privati negli assembly di pari o inferiore attendibilità.

Creazione di domini dell'applicazione mediante sandbox

Per creare un dominio applicazione nel quale gli assembly siano in esecuzione con attendibilità parziale è necessario specificare l'insieme di autorizzazioni da concedere agli assembly utilizzando l'overload di metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]). Il modo più semplice per specificare la concessione è recuperare una concessione denominata dai criteri di sicurezza.

Nella procedura descritta di seguito viene creato un dominio applicazione mediante sandbox che esegue il codice con attendibilità parziale, per testare scenari in cui il codice generato può accedere solo a membri pubblici di tipi pubblici. In una procedura successiva viene mostrato come aggiungere RestrictedMemberAccess, per testare scenari in cui il codice generato può accedere a tipi e membri non pubblici in assembly che dispongono di autorizzazioni uguali o inferiori.

Per creare un dominio applicazione con attendibilità parziale

  1. Creare un set di autorizzazioni da concedere agli assembly nel dominio applicazione sandbox. In questo caso, viene utilizzato il set di autorizzazioni dell'area Internet.

    Dim ev As New Evidence()
    ev.AddHostEvidence(new Zone(SecurityZone.Internet))
    Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
    
    Evidence ev = new Evidence();
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));
    PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
    
  2. Creare un oggetto AppDomainSetup per inizializzare il dominio applicazione con un percorso dell'applicazione.

    Nota importanteImportante

    Per semplificare, in questo esempio di codice viene utilizzata la cartella corrente.Per eseguire codice realmente proveniente da Internet, utilizzare una cartella separata per il codice non attendibile, come descritto in Procedura: eseguire codice parzialmente attendibile in un oggetto sandbox.

    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
  3. Creare il dominio applicazione, specificando le informazioni di configurazione del dominio e il set di concessioni per tutti gli assembly eseguiti nel dominio.

    Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)
    
    AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);
    

    L'ultimo parametro dell'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) consente di specificare un insieme di assembly che devono essere concessi in attendibilità totale, invece della concessione del dominio applicazione. Non è necessario specificare gli assembly .NET Framework utilizzati dall'applicazione, perché si trovano nella Global Assembly Cache. Gli assembly della Global Assembly Cache sono sempre completamente attendibili. È possibile utilizzare questo parametro per specificare assembly con nome non sicuro che non si trovano nella Global Assembly Cache.

Aggiunta di RestrictedMemberAccess ai domini creati mediante sandbox

Le applicazioni host possono consentire a metodi dinamici ospitati anonimamente di accedere ai dati privati in assembly con livelli di attendibilità uguali o inferiori al livello di attendibilità dell'assembly che genera il codice. Per attivare la possibilità limitata di ignorare i controlli di visibilità Just-In-Time (JIT) l'applicazione host aggiunge un oggetto ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess (RMA) alla concessione.

Ad esempio, un host potrebbe concedere alle applicazioni Internet autorizzazioni Internet più RMA, in modo che un'applicazione Internet possa generare codice che accede a dati privati nei propri assembly. Poiché l'accesso è limitato agli assembly di attendibilità uguale o inferiore, un'applicazione Internet non può accedere a membri di assembly di attendibilità totale ad esempio gli assembly di .NET Framework.

NotaNota

Per impedire l'aumento dei privilegi, quando vengono costruiti i metodi dinamici ospitati anonimamente, vengono incluse le informazioni sullo stack per l'assembly che genera.Quando viene chiamato il metodo, vengono verificate le informazioni sullo stack.Pertanto, un metodo dinamico ospitato anonimamente richiamato da codice di attendibilità totale è ancora limitato al livello di attendibilità dell'assembly che genera.

Per creare un dominio applicazione con attendibilità parziale più RMA

  1. Creare un nuovo oggetto ReflectionPermission con il flag RestrictedMemberAccess (RMA) e utilizzare il metodo PermissionSet.SetPermission per aggiungere l'autorizzazione al set di concessioni.

    pset.SetPermission( _
        New ReflectionPermission( _
            ReflectionPermissionFlag.RestrictedMemberAccess))
    
    pset.SetPermission(
        new ReflectionPermission(
            ReflectionPermissionFlag.RestrictedMemberAccess));
    

    Il metodo AddPermission consente di aggiungere l'autorizzazione alla concessione, se non è già inclusa. Se l'autorizzazione è già inclusa nella concessione, i flag specificati vengono aggiunti all'autorizzazione esistente.

    NotaNota

    RMA è una funzionalità di metodi dinamici ospitati anonimamente.Quando i metodi dinamici comuni ignorano i controlli di visibilità JIT, il codice emesso richiede attendibilità totale.

  2. Creare il dominio applicazione specificando le informazioni di configurazione del dominio e il set di concessioni.

    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)
    
    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);
    

Esecuzione di codice nei domini applicazione creati mediante sandbox

Nella procedura descritta di seguito viene illustrato come definire una classe utilizzando metodi eseguibili in un dominio applicazione, come creare un'istanza della classe nel dominio e come eseguire i relativi metodi.

Per definire ed eseguire un metodo in un dominio applicazione

  1. Definire una classe che deriva da MarshalByRefObject. In tal modo sarà possibile creare istanze della classe negli altri domini applicazione e fare chiamate al metodo attraverso limiti del dominio applicazione. In questo esempio la classe è denominata Worker.

    Public Class Worker
        Inherits MarshalByRefObject
    
    public class Worker : MarshalByRefObject
    {
    
  2. Definire un metodo pubblico che contiene il codice da eseguire. In questo esempio, il codice genera un semplice metodo dinamico, crea un delegato per eseguire il metodo e richiama il delegato.

    Public Sub SimpleEmitDemo()
    
        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)
    
        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub
    
    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);
    
        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }
    
  3. Nel programma principale, ottenere il nome visualizzato dell'assembly. Questo nome viene utilizzato quando si creano istanze della classe Worker nel dominio applicazione creato mediante sandbox.

    Dim asmName As String = [Assembly].GetExecutingAssembly().FullName
    
    String asmName = Assembly.GetExecutingAssembly().FullName;
    
  4. Nel programma principale, creare un dominio applicazione mediante sandbox, come descritto nella prima procedura di questa procedura dettagliata. Non è necessario aggiungere autorizzazioni al set di autorizzazioni Internet impostato, perché il metodo SimpleEmitDemo utilizza solo metodi pubblici.

  5. Nel programma principale, creare un'istanza della classe Worker nel dominio applicazione creato mediante sandbox.

    Dim w As Worker = _
        CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
    
    Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
    

    Il metodo CreateInstanceAndUnwrap crea l'oggetto nel dominio applicazione di destinazione e restituisce un proxy che può essere utilizzato per chiamare le proprietà e i metodi dell'oggetto.

    NotaNota

    Se si utilizza questo esempio di codice in Visual Studio, è necessario modificare il nome della classe per includere lo spazio dei nomi. Per impostazione predefinita, lo spazio dei nomi è il nome del progetto.Ad esempio, se il progetto è "PartialTrust", il nome della classe deve essere "PartialTrust.Worker".

  6. Aggiungere codice per chiamare il metodo SimpleEmitDemo. La chiamata viene sottoposta a marshalling attraverso il limite del dominio applicazione e il codice viene eseguito nel dominio applicazione creato mediante sandbox.

    w.SimpleEmitDemo()
    
    w.SimpleEmitDemo();
    

Utilizzo di metodi dinamici ospitati anonimamente

I metodi dinamici ospitati anonimamente sono associati a un assembly trasparente fornito dal sistema. Il codice in essi contenuto è quindi trasparente. I metodi dinamici comuni, per contro, devono essere associati a un modulo esistente (specificato direttamente o derivato da un tipo associato) e assumono il livello di sicurezza da tale modulo.

NotaNota

L'unico modo per associare un metodo dinamico all'assembly che fornisce hosting anonimo è utilizzare i costruttori descritti nella procedura riportata di seguito.Non è possibile specificare in modo esplicito un modulo nell'assembly di hosting anonimo.

I metodi dinamici comuni hanno accesso ai membri interni del modulo ai quali sono associati, o ai membri privati del tipo a cui sono associati. I metodi dinamici ospitati anonimamente sono isolati da codice diverso, pertanto non hanno accesso ai dati privati. Tuttavia, hanno una possibilità limitata di ignorare i controlli di visibilità JIT per accedere ai dati privati. Questa possibilità è limitata agli assembly con livelli di attendibilità uguali o inferiori al livello di attendibilità dell'assembly che genera il codice.

Per impedire l'aumento dei privilegi, quando vengono costruiti i metodi dinamici ospitati anonimamente, vengono incluse le informazioni sullo stack per l'assembly che genera. Quando viene chiamato il metodo, vengono verificate le informazioni sullo stack. Un metodo dinamico ospitato anonimamente richiamato da codice di attendibilità totale è ancora limitato al livello di attendibilità dell'assembly che lo ha generato.

Per utilizzare metodi dinamici ospitati anonimamente

  • Creare un metodo dinamico ospitato anonimamente utilizzando un costruttore che non specifica un modulo o un tipo associato.

    Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
    Dim il As ILGenerator = meth.GetILGenerator()
    il.EmitWriteLine("Hello, World!")
    il.Emit(OpCodes.Ret)
    
    DynamicMethod meth = new DynamicMethod("", null, null);
    ILGenerator il = meth.GetILGenerator();
    il.EmitWriteLine("Hello, World!");
    il.Emit(OpCodes.Ret);
    

    Se un metodo dinamico ospitato anonimamente utilizza solo tipi e metodi pubblici, non richiede accesso limitato al membro e non deve ignorare i controlli di visibilità di JIT.

    Per generare un metodo dinamico non sono necessarie autorizzazioni speciali, ma il codice generato richiede le autorizzazioni obbligatorie per i tipi e i metodi che utilizza. Ad esempio, se il codice generato chiama un metodo che accede a un file, richiede FileIOPermission. Se il livello di attendibilità non include tale autorizzazione, viene generata un'eccezione di sicurezza quando il codice generato viene eseguito. Il codice illustrato genera un metodo dinamico che utilizza solo il metodo Console.WriteLine. Pertanto, il codice può essere eseguito da percorsi parzialmente attendibili.

  • In alternativa, creare un metodo dinamico ospitato anonimamente con possibilità limitata di ignorare i controlli di visibilità JIT, utilizzando il costruttore DynamicMethod(String, Type, Type[], Boolean) e specificando true per il parametro restrictedSkipVisibility.

    Dim meth As New DynamicMethod("", _
                                  GetType(Char), _
                                  New Type() {GetType(String)}, _
                                  True)
    
    DynamicMethod meth = new DynamicMethod("",
                                           typeof(char), 
                                           new Type[] { typeof(String) }, 
                                           true);
    

    La limitazione consiste nel fatto che il metodo dinamico ospitato anonimamente può accedere ai dati privati solo in assembly con livelli di attendibilità uguali o inferiori al livello di attendibilità dell'assembly che genera il codice. Ad esempio, se il metodo dinamico viene eseguito con attendibilità Internet, può accedere ai dati privati in altri assembly eseguiti anch'essi con attendibilità Internet, ma non ai dati privati in assembly di .NET Framework. Gli assembly di .NET Framework vengono installati nella Global Assembly Cache e sono sempre completamente attendibili.

    I metodi dinamici ospitati anonimamente possono utilizzare questa possibilità limitata per ignorare i controlli di visibilità JIT solo se l'applicazione host concede autorizzazioni ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess. La richiesta di questa autorizzazione viene fatta quando viene richiamato il metodo.

    NotaNota

    Quando viene costruito un metodo dinamico, vengono incluse le informazioni dello stack di chiamate dell'assembly che lo genera.Pertanto, la richiesta viene fatta per le autorizzazioni dell'assembly che genera anziché per l'assembly che richiama il metodo.In tal modo si evita che il codice generato venga eseguito con autorizzazioni elevate.

    Nell'esempio di codice completo alla fine di questa procedura dettagliata vengono illustrati l'utilizzo e le limitazioni di accesso al membro. La classe Worker include un metodo che può creare metodi dinamici ospitati anonimamente con o senza la possibilità limitata di ignorare controlli di visibilità. Nell'esempio viene illustrato il risultato dell'esecuzione di tale metodo in domini applicazione con livelli di attendibilità diversi.

    NotaNota

    La possibilità limitata di ignorare i controlli di visibilità è una funzionalità di metodi dinamici ospitati anonimamente.Quando i metodi dinamici comuni ignorano i controlli di visibilità JIT, richiedono la concessione dell'attendibilità totale.

Esempio

Descrizione

Nell'esempio di codice riportato di seguito viene illustrato l'utilizzo del flag RestrictedMemberAccess per consentire ai metodi dinamici ospitati anonimamente di ignorare i controlli di visibilità JIT, ma solo quando il membro di destinazione è a un livello di attendibilità uguale o inferiore a quello dell'assembly che genera il codice.

Nell'esempio viene definita una classe Worker di cui può essere effettuato il marshalling attraverso limiti del dominio applicazione. La classe ha due overload di metodi AccessPrivateMethod che generano ed eseguono metodi dinamici. Il primo overload genera un metodo dinamico che chiama il metodo privato PrivateMethod della classe Worker e può generare il metodo dinamico con o senza controlli di visibilità JIT. Il secondo overload genera un metodo dinamico che accede alla proprietà internal (proprietàFriend in Visual Basic) della classe String.

Nell'esempio viene utilizzato un metodo di supporto per creare un set di concessioni limitato alle autorizzazioni Internet, quindi viene creato un dominio applicazione utilizzando l'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) per specificare che tutto il codice eseguito nel dominio utilizza questo set di concessioni. Nell'esempio viene creata un'istanza della classe Worker nel dominio applicazione e viene eseguito il metodo AccessPrivateMethod due volte.

  • La prima volta che viene eseguito il metodo AccessPrivateMethod vengono applicati i controlli di visibilità JIT. Il metodo dinamico ha esito negativo quando viene richiamato, perché i controlli di visibilità JIT gli impediscono di accedere al metodo privato.

  • La seconda volta che viene eseguito il metodo AccessPrivateMethod i controlli di visibilità JIT vengono ignorati. Il metodo dinamico ha esito negativo quando viene compilato, perché la concessione Internet non è sufficiente per ignorare i controlli di visibilità.

Nell'esempio, ReflectionPermission con ReflectionPermissionFlag.RestrictedMemberAccess viene aggiunto al set di concessioni. Nell'esempio viene creato quindi un secondo dominio, specificando che tutto il codice eseguito nel dominio possiede le autorizzazioni del nuovo set. Nell'esempio viene creata un'istanza della classe Worker nel nuovo dominio applicazione e vengono eseguiti entrambi gli overload del metodo AccessPrivateMethod.

  • Viene eseguito il primo overload del metodo AccessPrivateMethod e i controlli di visibilità JIT vengono ignorati. Il metodo dinamico compila ed esegue correttamente, perché l'assembly che genera il codice corrisponde all'assembly che contiene il metodo privato. Pertanto, i livelli di attendibilità sono uguali. Se l'applicazione che contiene la classe Worker ha molti assembly, lo stesso processo riuscirebbe per uno qualsiasi di tali assembly, perché sarebbero tutti allo stesso livello di attendibilità.

  • Viene eseguito il secondo overload del metodo AccessPrivateMethod e i controlli di visibilità JIT vengono di nuovo ignorati. Questa volta il metodo dinamico ha esito negativo quando viene compilato, perché tenta di accedere alla proprietà internalFirstChar della classe String. L'assembly che contiene la classe String è totalmente attendibile. Pertanto dispone di un livello di attendibilità superiore a quello dell'assembly che genera il codice.

Nel confronto viene illustrato come ReflectionPermissionFlag.RestrictedMemberAccess consente a codice parzialmente attendibile di ignorare i controlli di visibilità per altro codice parzialmente attendibile senza compromettere la sicurezza del codice attendibile.

Codice

Imports System
Imports System.Reflection.Emit
Imports System.Reflection
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Collections
Imports System.Diagnostics

' This code example works properly only if it is run from a fully 
' trusted location, such as your local computer.

' Delegates used to execute the dynamic methods.
'
Public Delegate Sub Test(ByVal w As Worker) 
Public Delegate Sub Test1() 
Public Delegate Function Test2(ByVal instance As String) As Char 

' The Worker class must inherit MarshalByRefObject so that its public 
' methods can be invoked across application domain boundaries.
'
Public Class Worker
    Inherits MarshalByRefObject

    Private Sub PrivateMethod() 
        Console.WriteLine("Worker.PrivateMethod()")
    End Sub 

    Public Sub SimpleEmitDemo()

        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)

        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub

    ' This overload of AccessPrivateMethod emits a dynamic method and
    ' specifies whether to skip JIT visiblity checks. It creates a 
    ' delegate for the method and invokes the delegate. The dynamic 
    ' method calls a private method of the Worker class.
    Overloads Public Sub AccessPrivateMethod( _
                       ByVal restrictedSkipVisibility As Boolean) 

        ' Create an unnamed dynamic method that has no return type,
        ' takes one parameter of type Worker, and optionally skips JIT
        ' visiblity checks.
        Dim meth As New DynamicMethod("", _
                                      Nothing, _
                                      New Type() { GetType(Worker) }, _
                                      restrictedSkipVisibility)

        ' Get a MethodInfo for the private method.
        Dim pvtMeth As MethodInfo = GetType(Worker).GetMethod( _
            "PrivateMethod", _
            BindingFlags.NonPublic Or BindingFlags.Instance)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target instance, onto the
        ' execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test = CType(meth.CreateDelegate(GetType(Test)), Test)
            Try
                t(Me)
            Catch ex As Exception
                Console.WriteLine("{0} was thrown when the delegate was invoked.", _
                    ex.GetType().Name)
            End Try
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub 


    ' This overload of AccessPrivateMethod emits a dynamic method that takes
    ' a string and returns the first character, using a private field of the 
    ' String class. The dynamic method skips JIT visiblity checks.
    Overloads Public Sub AccessPrivateMethod() 

        Dim meth As New DynamicMethod("", _
                                      GetType(Char), _
                                      New Type() {GetType(String)}, _
                                      True)

        ' Get a MethodInfo for the 'get' accessor of the private property.
        Dim pi As PropertyInfo = GetType(String).GetProperty( _
            "FirstChar", _
            BindingFlags.NonPublic Or BindingFlags.Instance) 
        Dim pvtMeth As MethodInfo = pi.GetGetMethod(True)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target string, onto the
        ' execution stack, call the 'get' accessor to put the result onto 
        ' the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test2 = CType(meth.CreateDelegate(GetType(Test2)), Test2)
            Dim first As Char = t("Hello, World!")
            Console.WriteLine("{0} is the first character.", first)
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub 
End Class

Friend Class Example

    ' The entry point for the code example.
    Shared Sub Main() 

        ' Get the display name of the executing assembly, to use when
        ' creating objects to run code in application domains.
        Dim asmName As String = [Assembly].GetExecutingAssembly().FullName

        ' Create the permission set to grant to other assemblies. In this
        ' case they are the permissions found in the Internet zone.
        Dim ev As New Evidence()
        ev.AddHostEvidence(new Zone(SecurityZone.Internet))
        Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))

        ' For simplicity, set up the application domain to use the 
        ' current path as the application folder, so the same executable
        ' can be used in both trusted and untrusted scenarios. Normally
        ' you would not do this with real untrusted code.
        Dim adSetup As New AppDomainSetup()
        adSetup.ApplicationBase = "."

        ' Create an application domain in which all code that executes is 
        ' granted the permissions of an application run from the Internet.
        Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. Note: If you build this code example in Visual Studio, 
        ' you must change the name of the class to include the default 
        ' namespace, which is the project name. For example, if the project
        ' is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Dim w As Worker = _
            CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo()

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, with JIT visibility checks enforced. The call fails 
        ' when the delegate is invoked.
        w.AccessPrivateMethod(False)

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. The call fails when
        ' the method is compiled.
        w.AccessPrivateMethod(True)


        ' Unload the application domain. Add RestrictedMemberAccess to the
        ' grant set, and use it to create an application domain in which
        ' partially trusted code can call private members, as long as the 
        ' trust level of those members is equal to or lower than the trust 
        ' level of the partially trusted code. 
        AppDomain.Unload(ad)
        pset.SetPermission( _
            New ReflectionPermission( _
                ReflectionPermissionFlag.RestrictedMemberAccess))
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. 
        w = CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Again, emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. This time compilation 
        ' succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(True)

        ' Finally, emit and invoke a dynamic method that calls an internal 
        ' method of the String class. The call fails, because the trust level
        ' of the assembly that contains String is higher than the trust level
        ' of the assembly that emits the dynamic method.
        w.AccessPrivateMethod()

    End Sub 
End Class 

' This code example produces the following output:
'
'Hello, World!
'MethodAccessException was thrown when the delegate was invoked.
'MethodAccessException was thrown when the delegate was invoked.
'Worker.PrivateMethod()
'MethodAccessException was thrown when the delegate was compiled.
' 
using System;
using System.Reflection.Emit;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Collections;
using System.Diagnostics;

// This code example works properly only if it is run from a fully 
// trusted location, such as your local computer.

// Delegates used to execute the dynamic methods.
//
public delegate void Test(Worker w);
public delegate void Test1();
public delegate char Test2(String instance);

// The Worker class must inherit MarshalByRefObject so that its public 
// methods can be invoked across application domain boundaries.
//
public class Worker : MarshalByRefObject
{
    private void PrivateMethod()
    {
        Console.WriteLine("Worker.PrivateMethod()");
    }

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);

        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }

    // This overload of AccessPrivateMethod emits a dynamic method and
    // specifies whether to skip JIT visiblity checks. It creates a 
    // delegate for the method and invokes the delegate. The dynamic 
    // method calls a private method of the Worker class.
    public void AccessPrivateMethod(bool restrictedSkipVisibility) 
    {
        // Create an unnamed dynamic method that has no return type,
        // takes one parameter of type Worker, and optionally skips JIT
        // visiblity checks.
        DynamicMethod meth = new DynamicMethod(
            "", 
            null, 
            new Type[] { typeof(Worker) }, 
            restrictedSkipVisibility);

        // Get a MethodInfo for the private method.
        MethodInfo pvtMeth = typeof(Worker).GetMethod("PrivateMethod",
            BindingFlags.NonPublic | BindingFlags.Instance);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target instance, onto the
        // execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and 
        // invoke it. 
        try 
        {
            Test t = (Test) meth.CreateDelegate(typeof(Test));
            try 
            {
                t(this);
            }
            catch (Exception ex) 
            {
                Console.WriteLine("{0} was thrown when the delegate was invoked.", 
                    ex.GetType().Name);
            }
        } 
        catch (Exception ex) 
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.", 
                ex.GetType().Name);
        }
    }

    // This overload of AccessPrivateMethod emits a dynamic method that takes
    // a string and returns the first character, using a private field of the 
    // String class. The dynamic method skips JIT visiblity checks.
    public void AccessPrivateMethod() 
    {
        DynamicMethod meth = new DynamicMethod("",
                                               typeof(char), 
                                               new Type[] { typeof(String) }, 
                                               true);

        // Get a MethodInfo for the 'get' accessor of the private property.
        PropertyInfo pi = typeof(System.String).GetProperty(
            "FirstChar",
            BindingFlags.NonPublic | BindingFlags.Instance);
        MethodInfo pvtMeth = pi.GetGetMethod(true);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target string, onto the
        // execution stack, call the 'get' accessor to put the result onto 
        // the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and 
        // invoke it. 
        try 
        {
            Test2 t = (Test2) meth.CreateDelegate(typeof(Test2));
            char first = t("Hello, World!");
            Console.WriteLine("{0} is the first character.", first);
        } 
        catch (Exception ex) 
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.", 
                ex.GetType().Name);
        }
    }


    // The entry point for the code example.
    static void Main()
    {
        // Get the display name of the executing assembly, to use when
        // creating objects to run code in application domains.
        String asmName = Assembly.GetExecutingAssembly().FullName;

        // Create the permission set to grant to other assemblies. In this
        // case they are the permissions found in the Internet zone.
        Evidence ev = new Evidence();
        ev.AddHostEvidence(new Zone(SecurityZone.Internet));
        PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));

        // For simplicity, set up the application domain to use the 
        // current path as the application folder, so the same executable
        // can be used in both trusted and untrusted scenarios. Normally
        // you would not do this with real untrusted code.
        AppDomainSetup adSetup = new AppDomainSetup();
        adSetup.ApplicationBase = ".";

        // Create an application domain in which all code that executes is 
        // granted the permissions of an application run from the Internet.
        AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted 
        // domain. Note: If you build this code example in Visual Studio, 
        // you must change the name of the class to include the default 
        // namespace, which is the project name. For example, if the project
        // is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo();

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, with JIT visibility checks enforced. The call fails 
        // when the delegate is invoked.
        w.AccessPrivateMethod(false);

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. The call fails when
        // the method is invoked.
        w.AccessPrivateMethod(true);


        // Unload the application domain. Add RestrictedMemberAccess to the
        // grant set, and use it to create an application domain in which
        // partially trusted code can call private members, as long as the 
        // trust level of those members is equal to or lower than the trust 
        // level of the partially trusted code. 
        AppDomain.Unload(ad);
        pset.SetPermission(
            new ReflectionPermission(
                ReflectionPermissionFlag.RestrictedMemberAccess));
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted 
        // domain. 
        w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Again, emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. This time compilation 
        // succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(true);

        // Finally, emit and invoke a dynamic method that calls an internal 
        // method of the String class. The call fails, because the trust level
        // of the assembly that contains String is higher than the trust level
        // of the assembly that emits the dynamic method.
        w.AccessPrivateMethod();
    }
}

/* This code example produces the following output:

Hello, World!
MethodAccessException was thrown when the delegate was invoked.
MethodAccessException was thrown when the delegate was invoked.
Worker.PrivateMethod()
MethodAccessException was thrown when the delegate was compiled.
 */

Compilazione del codice

  • Se si compila questo esempio di codice in Visual Studio, è necessario modificare il nome della classe per includere lo spazio dei nomi quando la si passa al metodo CreateInstanceAndUnwrap. Per impostazione predefinita, lo spazio dei nomi rappresenta il nome del progetto. Ad esempio, se il progetto è "PartialTrust", il nome della classe deve essere "PartialTrust.Worker".

Vedere anche

Attività

Procedura: eseguire codice parzialmente attendibile in un oggetto sandbox

Concetti

Problemi di sicurezza nella reflection emit