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

L’émission de réflexion utilise le même ensemble d’API en confiance totale ou partielle, mais certaines fonctionnalités nécessitent des autorisations spéciales dans le code avec confiance partielle. En outre, l’émission de réflexion a une fonctionnalité, des méthodes dynamiques hébergées anonymement, qui est conçue pour être utilisée avec une confiance partielle et par les assemblys transparents de sécurité.

Notes

Avant .NET Framework 3.5, l’émission de code nécessitait ReflectionPermission avec l’indicateur ReflectionPermissionFlag.ReflectionEmit. Par défaut, cette autorisation est comprise 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 seulement si elle avait l’attribut SecurityCriticalAttribute et exécutait aussi une méthode Assert pour ReflectionEmit. Ces bibliothèques nécessitent une revue minutieuse de la sécurité, car les erreurs de codage peuvent entraîner des failles de sécurité. .NET Framework 3.5 permet au code d’être émis dans des scénarios de confiance partielle sans émettre de demandes de sécurité, car la génération de code n’est pas fondamentalement une opération nécessitant des privilèges. Autrement dit, le code généré n'a pas plus d'autorisations que l'assembly qui l'émet. Ainsi, les bibliothèques qui émettent du code sont transparentes de sécurité et il devient inutile de déclarer ReflectionEmit puisque l’écriture d’une bibliothèque sécurisée ne nécessite pas une révision aussi approfondie de la sécurité.

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

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

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

Configuration des emplacements partiellement fiables

Les deux procédures suivantes montrent comment configurer des emplacements à partir desquels vous pouvez tester du code avec une confiance partielle.

  • La première procédure montre comment créer un domaine d’application sandbox dans lequel le code a des autorisations Internet.

  • La seconde procédure montre comment ajouter ReflectionPermission avec l’indicateur ReflectionPermissionFlag.RestrictedMemberAccess à un domaine d’application partiellement fiable pour activer l’accès aux données privées dans des assemblys d’une confiance inférieure ou égale.

Création de domaines d’application sandbox

Pour créer un domaine d’application dans lequel vos assemblys s’exécutent avec une confiance partielle, vous devez spécifier le jeu d’autorisations à accorder aux assemblys en utilisant la surcharge de la 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é auprès de la stratégie de sécurité.

La procédure suivante crée un domaine d’application sandbox qui exécute votre code avec une confiance partielle pour tester des scénarios dans lesquels le code émis peut accéder seulement à des membres publics de types public. La procédure qui vient après montre comment ajouter RestrictedMemberAccess pour tester des scénarios dans lesquels le code émis peut accéder aux types et aux membres non publics dans les assemblys bénéficiant d’autorisations inférieures ou égales.

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é.

    Evidence ev = new Evidence();
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));
    PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
    
    Dim ev As New Evidence()
    ev.AddHostEvidence(new Zone(SecurityZone.Internet))
    Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
    
  2. Créez un objet AppDomainSetup pour initialiser le domaine d’application avec un chemin d’application.

    Important

    Pour simplifier, cet exemple de code utilise le dossier actif. Pour exécuter du code qui provient d’Internet, utilisez un dossier distinct pour le code non fiable, comme décrit dans Guide pratique pour exécuter du code d’un niveau de confiance partiel dans un bac à sable (sandbox).

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Créez le domaine d’application en spécifiant les informations de configuration du domaine d’application et le jeu d’autorisations accordé pour tous les assemblys qui s’exécutent dans le domaine d’application.

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

    Le dernier paramètre de la surcharge de la méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) vous permet de spécifier un ensemble d’assemblys auxquels une confiance totale est accordée, à la place du jeu d’autorisations du domaine d’application. Il n’est pas nécessaire de spécifier les assemblys .NET Framework utilisés par votre application, car ces assemblys se trouvent dans le Global Assembly Cache. Les assemblys présents dans le Global Assembly Cache sont toujours totalement fiables. 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 à des domaines sandbox

Les applications hôtes peuvent autoriser les méthodes dynamiques hébergées anonymement à accéder aux données privées dans les assemblys qui ont des niveaux de confiance inférieurs ou égaux au niveau de confiance de l’assembly qui émet le code. Pour permettre cette possibilité limitée d’ignorer les contrôles de visibilité juste-à-temps (JIT), 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 plus RMA à des applications Internet, pour qu’une application Internet puisse émettre du code qui accède aux données privées dans ses propres assemblys. Étant donné que l’accès est limité aux assemblys de confiance inférieure ou égale, une application Internet ne peut pas accéder aux membres des assemblys entièrement fiables, comme les assemblys .NET Framework.

Notes

Pour empêcher une élévation de privilèges, les informations de pile de l’assembly émetteur sont incluses lors de la construction des méthodes dynamiques hébergées anonymement. Quand la méthode est appelée, les informations de pile sont vérifiées. Par conséquent, une méthode dynamique hébergée anonymement qui est appelée à partir d’un code totalement fiable est toujours 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 elle n’y est pas déjà. Si l’autorisation est déjà dans le jeu d’autorisations, les indicateurs spécifiés sont ajoutés à l’autorisation existante.

    Notes

    RMA est une fonctionnalité des méthodes dynamiques hébergées anonymement. Quand des 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 de configuration du domaine d’application et le jeu d’autorisations.

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

Exécution de code dans des domaines d’application 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. Cette opération vous permet de créer des instances de la classe dans d’autres domaines d’application et d’effectuer des appels de méthode à travers les limites du domaine d’application. Dans cet exemple, la classe est nommée Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Définissez une méthode publique qui contient le code que vous voulez 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 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();
    }
    
    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
    
  3. Dans votre programme principal, obtenez le nom d’affichage de votre assembly. Ce nom est utilisé quand vous créez des instances de la classe Worker dans le domaine d’application sandbox.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. Dans votre programme principal, créez un domaine d’application sandbox, comme décrit dans la première procédure de cet article. Vous ne devez pas ajouter des autorisations au jeu d’autorisations Internet, car la méthode SimpleEmitDemo utilise uniquement des méthodes publiques.

  5. Dans votre programme principal, créez une instance de la classe Worker dans le domaine d’application sandbox.

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
    
    Dim w As Worker = _
        CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), 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 les méthodes de l’objet.

    Notes

    Si vous utilisez ce code dans Visual Studio, vous devez changer le nom de la classe pour y inclure l’espace de noms. Par défaut, l’espace de noms est le nom du projet. Par exemple, si le projet est « PartialTrust », le nom de la classe doit être « PartialTrust.Worker ».

  6. Ajoutez le 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 sandbox.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Utilisation de méthodes dynamiques hébergées anonymement

Les méthodes dynamiques hébergées anonymement 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 doivent quant à elles être associées à un module existant (qu’il soit spécifié directement ou inféré depuis un type associé) et prendre leur niveau de sécurité de ce module.

Notes

La seule façon d’associer une méthode dynamique à l’assembly qui fournit l’hébergement anonyme est d’utiliser les constructeurs qui sont décrits dans la procédure suivante. Vous ne pouvez pas spécifier explicitement un module dans l’assembly hébergeur 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. Comme les méthodes dynamiques hébergées anonymement sont isolées du reste du code, elles n’ont pas accès aux données privées. Toutefois, elles ont une possibilité limitée d’ignorer les contrôles de visibilité JIT pour accéder aux données privées. Cette possibilité est limitée aux assemblys qui ont des niveaux de confiance inférieurs ou égaux au niveau de confiance de l’assembly qui émet le code.

Pour empêcher une élévation de privilèges, les informations de pile de l’assembly émetteur sont incluses lors de la construction des méthodes dynamiques hébergées anonymement. Quand la méthode est appelée, les informations de pile sont vérifiées. Une méthode dynamique hébergée anonymement qui est appelée à partir d’un code totalement fiable est toujours limitée au niveau de confiance de l’assembly émetteur.

Pour utiliser des méthodes dynamiques hébergées anonymement

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

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

    Si une méthode dynamique hébergée anonymement utilise seulement des méthodes et des types publics, elle ne nécessite pas un accès restreint aux membres et n’a pas à ignorer les contrôles de visibilité JIT.

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

  • Vous pouvez aussi créer une méthode dynamique hébergée anonymement avec une possibilité limitée d’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.

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

    La restriction est que la méthode dynamique hébergée anonymement peut accéder aux données privées seulement dans les assemblys avec des niveaux de confiance inférieurs ou égaux à celui de l’assembly émetteur. Par exemple, si la méthode dynamique s’exécute avec une confiance Internet, elle peut accéder aux données privées d’autres assemblys qui s’exécutent aussi avec la confiance Internet, mais elle ne peut pas accéder aux données privées des assemblys .NET Framework. Les assemblys .NET Framework sont installés dans le Global Assembly Cache et sont toujours entièrement fiables.

    Les méthodes dynamiques hébergées anonymement peuvent utiliser cette possibilité limitée d’ignorer les contrôles de visibilité JIT seulement si l’application hôte accorde ReflectionPermission avec l’indicateur ReflectionPermissionFlag.RestrictedMemberAccess. La demande de cette autorisation est effectuée quand la méthode est appelée.

    Notes

    Les informations de la pile des appels de l’assembly émetteur sont incluses lors de la construction de la méthode dynamique. Par conséquent, la demande porte sur les autorisations de l’assembly émetteur au lieu de l’assembly qui appelle la méthode. Ceci 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 montre l’utilisation et les limitations de l’accès restreint aux membres. Sa classe Worker comprend une méthode qui peut créer des méthodes dynamiques hébergées anonymement avec ou sans la possibilité limitée d’ignorer les contrôles de visibilité. L’exemple montre le résultat de l’exécution de cette méthode dans des domaines d’application qui ont des niveaux de confiance différents.

    Notes

    La possibilité limitée d’ignorer les contrôles de visibilité est une fonctionnalité des méthodes dynamiques hébergées anonymement. Quand des méthodes dynamiques ordinaires ignorent les contrôles de visibilité JIT, une confiance totale leur est accordée.

Exemple

Description

L’exemple de code suivant montre l’utilisation de l’indicateur RestrictedMemberAccess pour permettre aux méthodes dynamiques hébergées anonymement d’ignorer les contrôles de visibilité JIT, mais seulement quand le membre cible est à 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 à travers les limites du domaine d’application. La classe a deux surcharges de la 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 peut émettre la méthode dynamique avec ou sans contrôles de visibilité JIT. La deuxième surcharge émet une méthode dynamique qui accède à une propriété internal (la propriété Friend en 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 la méthode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pour spécifier que tout le code qui s’exécute dans le domaine utilise ce jeu d’autorisations. L’exemple crée une instance de la classe Worker dans le domaine d’application et exécute deux fois la méthode AccessPrivateMethod.

  • 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 quand elle est appelée, car 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, car 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 second domaine en spécifiant que tout le code qui s’exécute dans le domaine reçoit les autorisations du jeu d’autorisations. 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 se compile et s’exécute correctement, car 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, car 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, la méthode dynamique échoue lors de la compilation, car elle essaie d’accéder à la propriété internalFirstChar de la classe String. L’assembly qui contient la classe String est totalement fiable. Par conséquent, il est à un niveau de confiance plus élevé que l’assembly qui émet le code.

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

Code

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 = typeof(Worker).Assembly.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.
 */
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 = GetType(Worker).Assembly.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.
' 

Compilation du code

  • Si vous générez cet exemple de code dans Visual Studio, vous devez changer le nom de la classe pour inclure l’espace de noms quand 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 la classe doit être « PartialTrust.Worker ».

Voir aussi