Návod: Generování kódu ve scénářích částečné důvěryhodnosti

Reflection.Emit používá stejné rozhraní API v plné nebo částečné důvěryhodnosti, ale některé funkce vyžadují zvláštní oprávnění v částečně důvěryhodném kódu. Kromě toho má reflexe emitace funkci, anonymně hostované dynamické metody, která je navržena tak, aby byla použita s částečnou důvěrou a sestaveními transparentními z hlediska zabezpečení.

Poznámka:

Před .NET Frameworkem 3.5 bylo k vyzařování kódu potřeba ReflectionPermission s příznakem ReflectionPermissionFlag.ReflectionEmit. Toto oprávnění je ve výchozím nastavení součástí FullTrust a Intranet pojmenovaných sad oprávnění, ale ne v sadě oprávnění Internet. Proto lze knihovnu použít v prostředí částečné důvěryhodnosti pouze v případě, že má atribut SecurityCriticalAttribute a také spustí metodu Assert pro ReflectionEmit. Tyto knihovny vyžadují pečlivou kontrolu zabezpečení, protože chyby kódování by mohly vést k chybám zabezpečení. Rozhraní .NET Framework 3.5 umožňuje vygenerovat kód ve scénářích částečné důvěryhodnosti bez vystavení jakýchkoli požadavků na zabezpečení, protože generování kódu není ze své podstaty privilegovanou operací. To znamená, že vygenerovaný kód nemá více oprávnění než sestavení, které ho generuje. Toto umožňuje knihovnám, které generují kód, aby byly bezpečnostně transparentní a odstraňuje potřebu uplatnit ReflectionEmit, takže napsání zabezpečené knihovny nevyžaduje tak důkladnou bezpečnostní kontrolu.

Tento návod popisuje následující kroky:

Další informace o vydávání kódu ve scénářích částečné důvěry najdete v tématu Problémy se zabezpečením při použití Emit refleksí.

Úplný seznam kódu zobrazený v těchto postupech najdete v části Příklad na konci tohoto návodu.

Nastavení částečně důvěryhodných umístění

Následující dva postupy ukazují, jak nastavit lokality, ze kterých můžete testovat kód s částečnou důvěryhodností.

  • První postup ukazuje, jak vytvořit doménu aplikace v izolovaném prostoru (sandbox), ve které má kód udělená oprávnění k internetu.

  • Druhý postup ukazuje, jak přidat ReflectionPermission s příznakem ReflectionPermissionFlag.RestrictedMemberAccess do částečně důvěryhodné domény aplikace, aby byl přístup k privátním datům v sestaveních se stejnou nebo menší důvěryhodností.

Vytváření domén aplikací v izolovaném prostoru (sandbox)

Chcete-li vytvořit doménu aplikace, ve které jsou sestavení spuštěna s částečnou důvěryhodností, je nutné zadat sadu oprávnění, která mají být udělena sestavením pomocí přetížení funkce AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) pro vytvoření domény aplikace. Nejjednodušší způsob, jak určit sadu povolení, je načíst pojmenovanou sadu oprávnění ze bezpečnostní politiky.

Následující postup vytvoří sandboxovou aplikační doménu, která spustí váš kód s částečnou důvěryhodností, ke zkoumání scénářů, kdy emitovaný kód může přistupovat pouze k veřejným členům veřejných typů. Následující postup ukazuje, jak přidat RestrictedMemberAccess, k testovacím scénářům, ve kterých vygenerovaný kód může přistupovat k nepublikovaným typům a členům v sestaveních, která mají stejná nebo menší oprávnění.

Vytvoření domény aplikace s částečnou důvěrou

  1. Vytvořte oprávnění nastavená tak, aby se udělovala sestavením v doméně aplikace v izolovaném prostoru (sandbox). V tomto případě se používá sada oprávnění zóny Internetu.

    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. Vytvořte objekt AppDomainSetup pro inicializaci domény aplikace pomocí cesty aplikace.

    Důležité

    Pro zjednodušení tento příklad kódu používá aktuální složku. Ke spuštění kódu, který skutečně pochází z internetu, použijte samostatnou složku pro nedůvěryhodný kód, jak je popsáno v Postupy: Spuštění částečně důvěryhodného kódu v sandboxu.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Vytvořte doménu aplikace, zadejte informace o nastavení domény aplikace a sadu grantů pro všechna sestavení, která se spouští v doméně aplikace.

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

    Poslední parametr přetížené metody AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) vám umožňuje určit sadu sestavení, kterým má být poskytnuta plná důvěryhodnost, namísto sady oprávnění aplikační domény. Není nutné zadávat sestavení rozhraní .NET Framework, která vaše aplikace používá, protože tato sestavení jsou v globální mezipaměti sestavení. Sestavení v GAC jsou vždy plně důvěryhodná. Tento parametr můžete použít k určení sestavení se silným názvem, která nejsou v globální mezipaměti sestavení.

Přidání RestrictedMemberAccess do sandboxovaných domén

Hostitelské aplikace mohou povolit anonymní hostované dynamické metody, aby měly přístup k privátním datům v sestaveních, která mají úrovně důvěryhodnosti rovnající se nebo menší než úroveň důvěryhodnosti sestavení, která generuje kód. Aby bylo možné aktivovat omezenou schopnost přeskočit kontroly viditelnosti Just-In-Time (JIT), přidá hostitelská aplikace do sady udělení ReflectionPermission objekt s příznakem ReflectionPermissionFlag.RestrictedMemberAccess (RMA).

Hostitel může například udělit internetovým aplikacím oprávnění k internetu plus RMA, aby internetová aplikace mohla generovat kód, který přistupuje k privátním datům ve svých vlastních sestaveních. Vzhledem k tomu, že přístup je omezen na sestavení se stejnou nebo menší důvěryhodností, nemůže internetová aplikace přistupovat k členům plně důvěryhodných sestavení, jako jsou sestavení rozhraní .NET Framework.

Poznámka:

Aby se zabránilo zvýšení oprávnění, jsou informace o zásobníku pro emitující sestavení zahrnuty při vytváření anonymně hostovaných dynamických metod. Při vyvolání metody se zkontrolují informace o zásobníku. Anonymně hostovaná dynamická metoda, která je vyvolána z plně důvěryhodného kódu, je stále omezena na úroveň důvěryhodnosti vysílajícího sestavení.

Vytvoření domény aplikace s částečnou důvěrou a RMA

  1. Vytvořte nový objekt ReflectionPermission s příznakem RestrictedMemberAccess (RMA) a pomocí metody PermissionSet.SetPermission přidejte oprávnění k sadě udělení.

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

    Metoda AddPermission přidá oprávnění k sadě grantů, pokud ještě není zahrnuta. Pokud už je oprávnění součástí sady grantů, zadané příznaky se přidají k existujícímu oprávnění.

    Poznámka:

    RMA je funkce anonymně hostovaných dynamických metod. Když běžné dynamické metody přeskočí kontroly viditelnosti JIT, vygenerovaný kód vyžaduje úplnou důvěru.

  2. Vytvořte doménu aplikace, zadejte informace o nastavení domény aplikace a sadu grantů.

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

Spouštění kódu v izolovaných doménách aplikací (sandbox)

Následující postup vysvětluje, jak definovat třídu pomocí metod, které lze spustit v doméně aplikace, jak vytvořit instanci třídy v doméně domény a jak provést její metody.

Definování a spuštění metody v doméně aplikace

  1. Definujte třídu, která je odvozena z MarshalByRefObject. To umožňuje vytvářet instance třídy v jiných doménách aplikace a provádět volání metod napříč hranicemi domény aplikace. Třída v tomto příkladu má název Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Definujte veřejnou metodu obsahující kód, který chcete spustit. V tomto příkladu kód generuje jednoduchou dynamickou metodu, vytvoří delegáta pro spuštění metody a vyvolá delegáta.

    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. V hlavním programu získejte název sestavení, který se zobrazuje. Tento název se používá při vytváření instancí třídy Worker v izolovaném aplikačním doméně.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. V hlavním programu vytvořte doménu aplikace v izolovaném prostoru (sandbox), jak je popsáno v prvním postupu v tomto návodu. Do sady oprávnění Internet nemusíte přidávat žádná oprávnění, protože metoda SimpleEmitDemo používá pouze veřejné metody.

  5. V hlavním programu vytvořte instanci třídy Worker v doméně aplikace v izolovaném prostoru (sandbox).

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

    Metoda CreateInstanceAndUnwrap vytvoří objekt v cílové doméně aplikace a vrátí proxy server, který lze použít k volání vlastností a metod objektu.

    Poznámka:

    Pokud používáte tento kód v prostředí Visual Studio, musíte změnit název třídy tak, aby zahrnoval obor názvů. Ve výchozím nastavení je obor názvů názvem projektu. Pokud je například projekt "PartialTrust", název třídy musí být "PartialTrust.Worker".

  6. Přidejte kód pro volání metody SimpleEmitDemo. Volání je předáno přes hranici aplikační domény a kód je spuštěn v sandboxované doméně aplikace.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Použití anonymně hostovaných dynamických metod

Anonymně hostované dynamické metody jsou přidruženy k transparentnímu sestavení, které poskytuje systém. Proto je kód, který obsahují, transparentní. Běžné dynamické metody musí být na druhou stranu přidružené k existujícímu modulu (ať už přímo zadané nebo odvozené z přidruženého typu) a z daného modulu převezmou úroveň zabezpečení.

Poznámka:

Jediným způsobem, jak přidružit dynamickou metodu k sestavení, které poskytuje anonymní hostování, je použít konstruktory, které jsou popsány v následujícím postupu. Modul nelze explicitně zadat v anonymním hostitelském sestavení.

Běžné dynamické metody mají přístup k interním členům modulu, ke kterým jsou přidruženy, nebo k soukromým členům typu, ke kterým jsou přidruženi. Vzhledem k tomu, že dynamická metody hostované anonymně hostované jsou izolované od jiného kódu, nemají přístup k privátním datům. Mají ale omezenou schopnost přeskočit kontroly viditelnosti JIT, aby získaly přístup k privátním datům. Tato schopnost je omezena na sestavení, která mají úrovně důvěryhodnosti rovnající nebo menší než úroveň důvěryhodnosti sestavení, která generuje kód.

Aby se zabránilo zvýšení oprávnění, jsou informace o zásobníku pro emitující sestavení zahrnuty při vytváření anonymně hostovaných dynamických metod. Při vyvolání metody se zkontrolují informace o zásobníku. Dynamická metoda, která je vyvolána z plně důvěryhodného kódu, je stále omezena na úroveň důvěryhodnosti sestavení, která ho vygenerovala.

Použití anonymně hostovaných dynamických metod

  • Pomocí konstruktoru, který neurčoval přidružený modul nebo typ, vytvořte anonymně hostované dynamické metody.

    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)
    

    Pokud dynamická metoda hostovaná anonymně používá pouze veřejné typy a metody, nevyžaduje omezený přístup členů a nemusí přeskočit kontroly viditelnosti JIT.

    K vygenerování dynamické metody nejsou nutná žádná zvláštní oprávnění, ale vygenerovaný kód vyžaduje oprávnění vyžadovaná typy a metodami, které používá. Pokud například vygenerovaný kód volá metodu, která přistupuje k souboru, vyžaduje FileIOPermission. Pokud úroveň důvěryhodnosti toto oprávnění neobsahuje, při spuštění generovaného kódu se vyvolá výjimka zabezpečení. Zde uvedený kód generuje dynamickou metodu, která používá pouze metodu Console.WriteLine. Proto je možné kód spustit z částečně důvěryhodných umístění.

  • Případně vytvořte anonymně hostované dynamické metody s omezenou schopností přeskočit kontroly viditelnosti JIT pomocí konstruktoru DynamicMethod(String, Type, Type[], Boolean) a zadáním true pro parametr restrictedSkipVisibility.

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

    Omezení spočívá v tom, že dynamická metoda, která je anonymně hostovaná, má přístup k privátním datům pouze v sestaveních s úrovněmi důvěryhodnosti, která jsou rovna nebo menší než úroveň důvěryhodnosti vygenerovaného sestavení. Například pokud se dynamická metoda spouští s internetovou důvěrou, může přistupovat k privátním datům v jiných sestaveních, která jsou také spuštěna s internetovou důvěrou, ale nemůže přistupovat k privátním datům sestavení rozhraní .NET Framework. Sestavení .NET Framework jsou nainstalována do globální mezipaměti sestavení a jsou vždy plně důvěryhodná.

    Anonymně hostované dynamické metody mohou tuto omezenou schopnost přeskočit kontroly viditelnosti JIT pouze v případě, že hostitelská aplikace udělí ReflectionPermission s příznakem ReflectionPermissionFlag.RestrictedMemberAccess. O udělení tohoto oprávnění se žádá v okamžiku, kdy je metoda vyvolána.

    Poznámka:

    Informace o zásobníku volání pro vysílající sestavení jsou zahrnuty při vytváření dynamické metody. Proto se požadavek vztahuje na oprávnění vydávajícího sestavení namísto sestavení, které vyvolává metodu. Tím zabráníte spuštění vygenerovaného kódu se zvýšenými oprávněními.

    kompletní příklad kódu na konci tohoto návodu ukazuje použití a omezení omezeného přístupu členů. Její třída Worker obsahuje metodu, která může vytvořit anonymně hostované dynamické metody s nebo bez omezené schopnosti přeskočit kontroly viditelnosti, a příklad ukazuje výsledek spuštění této metody v aplikačních doménách s různými úrovněmi důvěry.

    Poznámka:

    Omezená schopnost přeskočit kontroly viditelnosti je funkce anonymně hostovaných dynamických metod. Pokud běžné dynamické metody přeskočí kontroly viditelnosti JIT, musí jim být udělena plná důvěra.

Příklad

Popis

Následující příklad kódu ukazuje použití příznaku RestrictedMemberAccess, aby anonymně hostované dynamické metody mohly přeskočit kontroly viditelnosti JIT, ale pouze v případě, že cílový člen má stejnou nebo nižší důvěryhodnost než sestavení, které vydává kód.

Příklad definuje Worker třídu, která se dá zařašovat přes hranice domény aplikace. Třída má dvě přetížení metod AccessPrivateMethod, která generují a provádějí dynamické metody. První přetížení vydává dynamickou metodu, která volá privátní metodu PrivateMethod třídy Worker, a může vydávat dynamickou metodu s kontrolami viditelnosti JIT nebo bez nich. Druhé přetížení generuje dynamickou metodu, která přistupuje k vlastnosti internal (vlastnostFriend v jazyce Visual Basic) třídy String.

Příklad používá pomocnou metodu k vytvoření sady grantů omezené na Internet oprávnění a pak vytvoří doménu aplikace pomocí přetížení metody AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) k určení, že veškerý kód, který se spouští v doméně, používá tuto sadu grantů. Příklad vytvoří instanci třídy Worker v doméně aplikace a dvakrát spustí AccessPrivateMethod metodu.

  • Při prvním spuštění metody AccessPrivateMethod se vynucují kontroly viditelnosti JIT. Dynamická metoda selže při vyvolání, protože kontroly viditelnosti JIT brání přístupu k privátní metodě.

  • Při druhém spuštění metody AccessPrivateMethod se kontroly viditelnosti JIT přeskočí. Dynamická metoda selže při kompilaci, protože sada udělení Internet neuděluje dostatečná oprávnění ke přeskočení kontrol viditelnosti.

Příklad přidá ReflectionPermission a ReflectionPermissionFlag.RestrictedMemberAccess do sady grantů. Příklad pak vytvoří druhou doménu a určí, že veškerý kód, který se spustí v doméně, má udělená oprávnění v nové sadě grantů. Příklad vytvoří instanci třídy Worker v nové aplikační doméně a provede obě přetížení metody AccessPrivateMethod.

  • Provede se první přetížení metody AccessPrivateMethod a kontroly viditelnosti JIT se přeskočí. Dynamická metoda se zkompiluje a úspěšně spustí, protože sestavení, které generuje kód, je stejné jako sestavení, které obsahuje privátní metodu. Proto jsou úrovně důvěryhodnosti stejné. Pokud aplikace, která obsahuje třídu Worker, měla několik sestavení, stejný proces by uspěl pro každé z těchto sestavení, protože by všechny byly na stejné úrovni důvěryhodnosti.

  • Druhé přetížení metody AccessPrivateMethod je provedeno, a znovu se přeskočí kontroly viditelnosti JIT. Tentokrát dynamická metoda selže při kompilaci, protože se pokusí přistoupit k vlastnosti internalFirstChar třídy String. Sestavení obsahující třídu String je plně důvěryhodné. Proto je na vyšší úrovni důvěryhodnosti než sestavení, které generuje kód.

Toto porovnání ukazuje, jak ReflectionPermissionFlag.RestrictedMemberAccess umožňuje částečně důvěryhodnému kódu přeskočit kontroly viditelnosti u jiných částečně důvěryhodných kódů, aniž by ohrozil bezpečnost důvěryhodného kódu.

Kód

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($"{ex.GetType().Name} was thrown when the delegate was invoked.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{ex.GetType().Name} was thrown when the delegate was compiled.");
        }
    }

    // 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($"{first} is the first character.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{ex.GetType().Name} was thrown when the delegate was compiled.");
        }
    }

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

Kompilace kódu

  • Pokud sestavíte tento příklad kódu v sadě Visual Studio, musíte změnit název třídy tak, aby zahrnoval obor názvů, když ho předáte metodě CreateInstanceAndUnwrap. Ve výchozím nastavení je namespace názvem projektu. Pokud je například projekt "PartialTrust", název třídy musí být "PartialTrust.Worker".

Viz také