Partager via


Procédure pas à pas : émission de code dans des scénarios de confiance partielle

L'émission de réflexion utilise le même jeu d'API dans les cas de confiance totale ou partielle, mais certaines fonctionnalités requièrent des autorisations spéciales dans le code d'un niveau de confiance partiel. De plus, l'émission de réflexion a une fonctionnalité, méthodes dynamiques hébergées de manière anonyme, qui est destinée à être utilisée avec la confiance partielle et par les assemblys Security Transparent.

RemarqueRemarque

Avant .NET Framework version 3.5, l'émission de code est requise ReflectionPermission avec l'indicateur ReflectionPermissionFlag.ReflectionEmit.Cette autorisation est incluse par défaut dans les jeux d'autorisations nommés FullTrust et Intranet, mais pas dans le jeu d'autorisations Internet.Par conséquent, une bibliothèque pourrait être utilisée avec une confiance partielle uniquement si elle dispose de l'attribut SecurityCriticalAttribute et si elle exécute une méthode Assert pour ReflectionEmit. Ces bibliothèques nécessitent une révision de sécurité méticuleuse, car les erreurs de codage pourraient provoquer des failles de sécurité..NET Framework 3.5 autorise l'émission de code dans des scénarios de confiance partielle sans émission de demandes de sécurité, parce que la génération du code n'est pas fondamentalement une opération privilégiée.Autrement dit, le code généré n'a pas plus d'autorisations que l'assembly qui l'émet.Cela permet aux bibliothèques qui émettent du code d'être Security Transparent et évite d'avoir à déclarer ReflectionEmit, de sorte que l'écriture d'une bibliothèque sécurisée ne nécessite pas de révision de sécurité approfondie.

Cette procédure pas à pas décrit les tâches suivantes :

  • Installation d'un bac à sable (sandbox) simple pour le test de code d'un niveau de confiance partiel.

    Remarque importanteImportant

    Il s'agit d'une méthode simple pour expérimenter du code avec un niveau de confiance partiel.Pour exécuter du code qui provient réellement d'emplacements non fiable, consultez Comment : exécuter du code d'un niveau de confiance partiel dans un bac à sable (sandbox).

  • Exécution du code dans les domaines d'application de confiance partielle.

  • Utilisation de méthodes dynamiques hébergées de manière anonyme pour émettre et exécuter du code de confiance partielle.

Pour plus d'informations sur l'émission du code dans les scénarios de confiance partielle, consultez Problèmes de sécurité dans l'émission de réflexion.

Pour obtenir la liste complète du code utilisé dans ces procédures, consultez la section Exemple à la fin de cette procédure pas à pas.

Installation d'emplacements de confiance partielle

Les deux procédures suivantes indiquent comment installer des emplacements à partir desquels vous pouvez tester du code avec un niveau de confiance partiel.

  • La première procédure explique comment créer un domaine d'application sandbox dans lequel le code bénéficie d'autorisations Internet.

  • La deuxième procédure indique comment ajouter ReflectionPermission avec l'indicateur ReflectionPermissionFlag.RestrictedMemberAccess à un domaine d'application partiellement fiable, pour permettre l'accès à des données privées dans des assemblys de confiance égale ou inférieure.

Création de domaines d'application en bac à sable (Sandboxed)

Pour créer un domaine d'application dans lequel vos assemblys s'exécutent avec la confiance partielle, vous devez spécifier le jeu d'autorisations à accorder aux assemblys en utilisant la surcharge de méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pour créer le domaine d'application. Pour spécifier le jeu d'autorisations, le plus simple est de récupérer un jeu d'autorisations nommé à partir de la stratégie de sécurité.

La procédure suivante crée un domaine d'application en bac à sable (sandbox) qui exécute votre code avec une confiance partielle, afin de tester des scénarios dans lesquels le code émis peut accéder uniquement aux membres publics des types publics. Une procédure suivante montre comment ajouter RestrictedMemberAccess, afin de tester des scénarios dans lesquels le code émis peut accéder aux types non public et aux membres dans les assemblys bénéficiant d'autorisations égales ou moindres.

Pour créer un domaine d'application avec une confiance partielle

  1. Créez un jeu d'autorisations à accorder aux assemblys dans le domaine d'application sandbox. Dans ce cas, le jeu d'autorisations de la zone Internet est utilisé.

    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. Créez un objet AppDomainSetup pour initialiser le domaine d'application avec un chemin d'accès d'application.

    Remarque importanteImportant

    Pour des raisons de simplicité, cet exemple de code utilise le dossier actif.Pour exécuter du code qui provient réellement d'Internet, utilisez un dossier séparé pour le code non fiable, comme décrit dans Comment : exécuter du code d'un niveau de confiance partiel dans un bac à sable (sandbox).

    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
  3. Créez le domaine d'application, en spécifiant les informations d'installation du domaine d'application et le jeu d'autorisations pour tous les assemblys exécutés dans le domaine d'application.

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

    Le dernier paramètre de la surcharge de méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) vous permet de spécifier un jeu des assemblys qui bénéficient de la confiance totale, à la place du jeu d'autorisations du domaine d'application. Vous n'avez pas à spécifier les assemblys .NET Framework que votre application utilise, parce que ces assemblys sont dans le Global Assembly Cache. Les assemblys dans le Global Assembly Cache ont toujours un niveau de confiance total. Vous pouvez utiliser ce paramètre pour spécifier des assemblys avec nom fort qui ne sont pas dans le Global Assembly Cache.

Ajout de RestrictedMemberAccess aux domaines en bac à sable (sandbox)

Les applications hôtes peuvent permettre aux méthodes dynamiques hébergées de manière anonyme d'avoir accès aux données privées dans les assemblys bénéficiant de niveaux de confiance inférieurs ou égaux au niveau de confiance de l'assembly qui émet le code. Pour permettre à cette capacité limitée d'ignorer les vérifications de visibilité JIT (juste-à-temps), l'application hôte ajoute un objet ReflectionPermission avec l'indicateur ReflectionPermissionFlag.RestrictedMemberAccess (RMA) au jeu d'autorisations.

Par exemple, un hôte peut accorder des autorisations Internet aux applications Internet plus RMA, afin qu'une application Internet puisse émettre du code qui accède aux données privées dans ses propres assemblys. Dans la mesure où l'accès est limité aux assemblys de confiance inférieure ou égale une application Internet ne peut pas accéder aux membres d'assemblys d'un niveau de confiance total tels que les assemblys .NET Framework.

RemarqueRemarque

Pour empêcher l'élévation de privilège, des informations de la pile pour l'assembly émetteur sont incluses lorsque des méthodes dynamiques hébergées de manière anonyme sont construites.Lorsque la méthode est appelée, les informations de la pile sont vérifiées.Ainsi, une méthode dynamique hébergée de manière anonyme qui est appelée à partir d'un code de niveau de confiance total est encore limitée au niveau de confiance de l'assembly émetteur.

Pour créer un domaine d'application avec une confiance partielle plus RMA

  1. Créez un objet ReflectionPermission avec l'indicateur RestrictedMemberAccess (RMA) et utilisez la méthode PermissionSet.SetPermission pour ajouter l'autorisation au jeu d'autorisations.

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

    La méthode AddPermission ajoute l'autorisation au jeu d'autorisations, si ce n'est déjà fait. Si l'autorisation est déjà incluse dans le jeu d'autorisations, les indicateurs spécifiés sont ajoutés à l'autorisation existante.

    RemarqueRemarque

    RMA est une fonctionnalité de méthodes dynamiques hébergées de manière anonyme.Lorsque les méthodes dynamiques ordinaires ignorent les contrôles de visibilité JIT, le code émis nécessite une confiance totale.

  2. Créez le domaine d'application, en spécifiant les informations d'installation du domaine d'application et le jeu d'autorisations.

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

Exécution du code dans des domaines d'application en bac de sable (sandbox)

La procédure suivante explique comment définir une classe en utilisant des méthodes qui peuvent être exécutées dans un domaine d'application, comment créer une instance de la classe dans le domaine, et comment exécuter ses méthodes.

Pour définir et exécuter une méthode dans un domaine d'application

  1. Définissez une classe qui dérive de MarshalByRefObject. Cela vous permet de créer des instances de la classe dans d'autres domaines d'application et faire des appels de méthode au-delà des limites de domaine d'application. Dans cet exemple, la classe s'appelle Worker.

    Public Class Worker
        Inherits MarshalByRefObject
    
    public class Worker : MarshalByRefObject
    {
    
  2. Définissez une méthode publique qui contient le code à exécuter. Dans cet exemple, le code émet une méthode dynamique simple, crée un délégué pour exécuter la méthode et appelle le délégué.

    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. Dans votre programme principal, obtenez le nom complet de votre assembly. Ce nom est utilisé lorsque vous créez des instances de la classe Worker dans le domaine d'application en bac à sable (sandbox).

    Dim asmName As String = [Assembly].GetExecutingAssembly().FullName
    
    String asmName = Assembly.GetExecutingAssembly().FullName;
    
  4. Dans votre programme principal, créez un domaine d'application en bac à sable (sandbox), comme décrit dans la première procédure de cette procédure pas à pas. Vous n'avez à ajouter aucune autorisation au jeu d'autorisations Internet, parce que la méthode SimpleEmitDemo utilise des méthodes publiques uniquement.

  5. Dans votre programme principal, créez une instance de la classe Worker dans le domaine d'application en bac à sable (sandbox).

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

    La méthode CreateInstanceAndUnwrap crée l'objet dans le domaine d'application cible et retourne un proxy qui peut être utilisé pour appeler les propriétés et méthodes de l'objet.

    RemarqueRemarque

    Si vous utilisez cet exemple de code dans Visual Studio, vous devez modifier le nom de la classe pour inclure l'espace de noms. Par défaut, il s'agit du nom du projet.Par exemple, si le projet est « PartialTrust », le nom de classe doit être « PartialTrust.Worker ».

  6. Ajoutez du code pour appeler la méthode SimpleEmitDemo. L'appel est marshalé à travers la limite du domaine d'application, et le code est exécuté dans le domaine d'application placée en bac à sable (sandbox).

    w.SimpleEmitDemo()
    
    w.SimpleEmitDemo();
    

Utilisation des méthodes dynamiques hébergées de manière anonyme

Les méthodes dynamiques hébergées de manière anonyme sont associées à un assembly transparent fourni par le système. Par conséquent, le code qu'elles contiennent est transparent. Les méthodes dynamiques ordinaires, en revanche, doivent être associées à un module existant (directement spécifié ou déduit d'un type associé) et dérivent leur niveau de sécurité de ce module.

RemarqueRemarque

La seule méthode pour associer une méthode dynamique à l'assembly qui fournit l'hébergement anonyme est d'utiliser les constructeurs décrits dans la procédure suivante.Vous ne pouvez pas spécifier explicitement de module dans l'assembly d'hébergement anonyme.

Les méthodes dynamiques ordinaires ont accès aux membres internes du module auquel elles sont associées, ou aux membres privés du type auquel elles sont associées. Dans la mesure où les méthodes dynamiques hébergées de manière anonyme sont isolées du reste du code, elles n'ont pas accès aux données privées. Toutefois, elles ont une capacité restreinte d'ignorer les vérifications de visibilité JIT pour accéder aux données privées. Cette capacité est limitée aux assemblys qui ont des niveaux de confiance inférieure ou égaux au niveau de confiance de l'assembly qui émet le code.

Pour empêcher l'élévation de privilège, des informations de la pile pour l'assembly émetteur sont incluses lorsque des méthodes dynamiques hébergées de manière anonyme sont construites. Lorsque la méthode est appelée, les informations de la pile sont vérifiées. Une méthode dynamique hébergée de manière anonyme qui est appelée à partir d'un code de niveau de confiance total est encore limitée au niveau de confiance de l'assembly à l'origine de son émission.

Pour utiliser des méthodes dynamiques hébergées de manière anonyme

  • Créez une méthode dynamique hébergée de manière anonyme en utilisant un constructeur qui ne spécifie pas un module associé ou type.

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

    Si une méthode dynamique hébergée de manière anonyme utilise uniquement des types publics et des méthodes, elle ne requiert pas d'accès de membre restreint et n'a pas à ignorer les contrôles de visibilité JIT.

    Aucune autorisation spéciale n'est requise pour émettre une méthode dynamique, mais le code émis requiert les autorisations demandées par les types et méthodes qu'il utilise. Par exemple, si le code émis appelle une méthode qui accède à un fichier, il requiert FileIOPermission. Si le niveau de confiance n'inclut pas cette autorisation, une exception de sécurité est levée lorsque le code émis est exécuté. Le code montré ici émet une méthode dynamique qui utilise uniquement la méthode Console.WriteLine. Par conséquent, le code peut être exécuté à partir d'emplacements de confiance partielle.

  • Ou bien, créez une méthode dynamique hébergée de manière anonyme avec capacité restreinte pour ignorer les contrôles de visibilité JIT, en utilisant le constructeur DynamicMethod(String, Type, Type[], Boolean) et en spécifiant true pour le paramètre 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 restriction est que la méthode dynamique hébergée de manière anonyme peut accéder uniquement aux données privées dans les assemblys avec des niveaux de confiance inférieurs ou égaux au niveau de confiance de l'assembly d'émission. Par exemple, si la méthode dynamique s'exécute avec l'approbation Internet, elle peut accéder aux données privées d'autres assemblys également exécutés avec l'approbation Internet, mais elle ne peut pas accéder aux données privées d'assemblys .NET Framework. Les assemblys .NET Framework sont installés dans le Global Assembly Cache et présentent toujours un niveau de confiance totale.

    Les méthodes dynamiques hébergées de manière anonyme peuvent utiliser cette capacité restreinte pour ignorer les vérifications de visibilité JIT uniquement si l'application hôte accorde ReflectionPermission avec l'indicateur ReflectionPermissionFlag.RestrictedMemberAccess. La demande pour cette autorisation est faite lorsque la méthode est appelée.

    RemarqueRemarque

    Les informations de la pile d'appel pour l'assembly d'émission sont incluses lors de la construction de la méthode dynamique.Par conséquent, la demande est faite par rapport aux autorisations de l'assembly d'émission et non de l'assembly qui appelle la méthode.Cela empêche l'exécution du code émis avec des autorisations élevées.

    L'exemple de code complet à la fin de cette procédure pas à pas illustre l'utilisation et les limitations d'accès de membre restreint. Sa classe Worker inclut une méthode qui peut créer des méthodes dynamiques hébergées de manière anonyme avec ou sans la capacité restreinte d'ignorer les contrôles de visibilité, et l'exemple montre le résultat de l'exécution de cette méthode dans les domaines d'application qui ont des niveaux de confiance différents.

    RemarqueRemarque

    La capacité restreinte d'ignorer les contrôles de visibilité est une caractéristique des méthodes dynamiques hébergées de manière anonyme.Lorsque les méthodes dynamiques ordinaires ignorent les contrôles de visibilité JIT, elles doivent se voir accorder une confiance totale.

Exemple

Description

L'exemple de code suivant montre l'utilisation de l'indicateur RestrictedMemberAccess pour permettre aux méthodes dynamiques hébergées de manière anonyme d'ignorer les contrôles de visibilité JIT, mais uniquement lorsque le membre cible a un niveau de confiance inférieur ou égal à celui de l'assembly qui émet le code.

L'exemple définit une classe Worker qui peut être marshalée au-delà des limites du domaine d'application. La classe a deux surcharges de méthode AccessPrivateMethod qui émettent et exécutent des méthodes dynamiques. La première surcharge émet une méthode dynamique qui appelle la méthode PrivateMethod privée de la classe Worker, et elle peut émettre la méthode dynamique avec ou sans contrôles de visibilité JIT. La seconde surcharge émet une méthode dynamique qui accède à une propriété internal (propriétéFriend dans Visual Basic) de la classe String.

L'exemple utilise une méthode d'assistance pour créer un jeu d'autorisations limité aux autorisations Internet, puis crée un domaine d'application, en utilisant la surcharge de méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pour spécifier que tout le code qui s'exécute dans ce domaine utilise ce jeu d'autorisations. L'exemple crée une instance de la classe Worker dans le domaine d'application et exécute la méthode AccessPrivateMethod deux fois.

  • La première fois que la méthode AccessPrivateMethod est exécutée, les contrôles de visibilité JIT sont appliqués. La méthode dynamique échoue lorsqu'elle est appelée, parce que les contrôles de visibilité JIT l'empêchent d'accéder à la méthode privée.

  • La seconde fois que la méthode AccessPrivateMethod est exécutée, les contrôles de visibilité JIT sont ignorés. La méthode dynamique échoue lors de la compilation, parce que le jeu d'autorisations Internet n'accorde pas d'autorisations suffisantes pour ignorer les contrôles de visibilité.

L'exemple ajoute ReflectionPermission avec ReflectionPermissionFlag.RestrictedMemberAccess au jeu d'autorisations. L'exemple crée ensuite un deuxième domaine, en spécifiant que les autorisations du nouveau jeu d'autorisations sont accordées à l'ensemble du code qui s'exécute dans le domaine. L'exemple crée une instance de la classe Worker dans le nouveau domaine d'application et exécute les deux surcharges de la méthode AccessPrivateMethod.

  • La première surcharge de la méthode AccessPrivateMethod est exécutée et les contrôles de visibilité JIT sont ignorés. La méthode dynamique est compilée et exécutée avec succès, parce que l'assembly qui émet le code est le même que l'assembly qui contient la méthode privée. Par conséquent, les niveaux de confiance sont égaux. Si l'application qui contient la classe Worker avait plusieurs assemblys, le même processus réussirait pour chacun de ces assemblys, parce qu'ils seraient tous au même niveau de confiance.

  • La seconde surcharge de la méthode AccessPrivateMethod est exécutée et les contrôles de visibilité JIT sont à nouveau ignorés. Cette fois-ci, la méthode dynamique échoue lors de la compilation, parce qu'elle essaie d'accéder à la propriété internal FirstChar de la classe String. L'assembly qui contient la classe String est d'un niveau de confiance suffisant. Par conséquent, il s'agit d'un niveau de confiance supérieur à celui de l'assembly qui émet le code.

Cette comparaison montre comment ReflectionPermissionFlag.RestrictedMemberAccess permet à un code de niveau de confiance partiel d'ignorer les contrôles de visibilité pour un autre code de niveau de confiance partiel sans compromettre la sécurité du code de confiance.

Code

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.
 */

Compilation du code

  • Si vous générez cet exemple de code dans Visual Studio, vous devez modifier le nom de la classe pour inclure l'espace de noms lorsque vous le passez à la méthode CreateInstanceAndUnwrap. Par défaut, l'espace de noms est le nom du projet. Par exemple, si le projet est « PartialTrust », le nom de classe doit être « PartialTrust.Worker ».

Voir aussi

Tâches

Comment : exécuter du code d'un niveau de confiance partiel dans un bac à sable (sandbox)

Concepts

Problèmes de sécurité dans l'émission de réflexion