Návod: Vytváření kódu ve scénářích s částečnou důvěryhodností

Generování reflexe používá stejnou sadu rozhraní API v plném nebo částečném vztahu důvěryhodnosti, ale některé funkce vyžadují speciální oprávnění v částečně důvěryhodném kódu. Kromě toho má generování reflexe funkci anonymně hostovaných dynamických metod, která je navržena pro použití s částečnou důvěryhodností a sestaveními transparentními zabezpečením.

Poznámka

Před rozhraním .NET Framework 3.5 se vygeneruje požadovaný ReflectionPermission kód s příznakem ReflectionPermissionFlag.ReflectionEmit . Toto oprávnění je ve výchozím nastavení zahrnuto v FullTrust pojmenovaných sadách oprávnění a Intranet , ale ne v Internet sadě oprávnění. Proto lze knihovnu použít z částečného vztahu důvěryhodnosti pouze v případě, že měla SecurityCriticalAttribute atribut a také spustila metodu Assert pro ReflectionEmit. Takové knihovny vyžadují pečlivou kontrolu zabezpečení, protože chyby kódování můžou vést k chybám zabezpečení. Rozhraní .NET Framework 3.5 umožňuje generování kódu ve scénářích s částečnou důvěryhodností bez požadavků na zabezpečení, protože generování kódu není ze své podstaty privilegovaná operace. To znamená, že vygenerovaný kód nemá více oprávnění než sestavení, které ho generuje. To umožňuje knihovnám, které generují kód, být transparentní z hlediska zabezpečení a odstraňuje nutnost prosadit ReflectionEmit, takže zápis zabezpečené knihovny nevyžaduje tak důkladnou kontrolu zabezpečení.

Tento návod znázorňuje následující úlohy:

Další informace o generování kódu ve scénářích částečné důvěryhodnosti najdete v tématu Problémy se zabezpečením v generování reflexe.

Úplný seznam kódu zobrazeného 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 umístění, 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é jsou kódu udělena oprávnění k internetu.

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

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

Chcete-li vytvořit doménu aplikace, ve které vaše sestavení běží s částečným vztahem důvěryhodnosti, je nutné určit sadu oprávnění, která mají být udělena sestavením pomocí AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) přetížení metody k vytvoření domény aplikace. Nejjednodušší způsob, jak určit sadu udělení, je načíst pojmenovanou sadu oprávnění ze zásad zabezpečení.

Následující postup vytvoří doménu aplikace v izolovaném prostoru (sandbox), která spouští váš kód s částečnou důvěryhodností a otestuje scénáře, ve kterých může generovaný kód přistupovat pouze k veřejným členům veřejných typů. Následující postup ukazuje, jak přidat RestrictedMemberAccess, do testovacích scénářů, ve kterých může generovaný kód přistupovat k neveřejné typy a členy v sestaveních, kterým jsou udělena stejná nebo menší oprávnění.

Vytvoření domény aplikace s částečným vztahem důvěryhodnosti

  1. Vytvořte sadu oprávnění, která se uděluje sestavením v doméně aplikace v izolovaném prostoru (sandbox). V tomto případě se použije sada oprávnění zóny Internet.

    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 AppDomainSetup objekt 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. Pokud chcete spustit kód, který ve skutečnosti pochází z internetu, použijte pro nedůvěryhodný kód samostatnou složku, jak je popsáno v tématu 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 a zadejte informace o nastavení domény aplikace a sadu oprávnění 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 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) přetížení metody umožňuje určit sadu sestavení, která mají být udělena úplný vztah důvěryhodnosti namísto sady udělení oprávnění domény aplikace. 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í .NET Framework. Sestavení v globální mezipaměti sestavení (GPA) 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í (GPA).

Přidání RestrictedMemberAccess do domén v izolovaném prostoru (sandbox)

Hostitelské aplikace mohou povolit anonymně hostovaným dynamickým metodám přístup k privátním datům v sestaveních, která mají úroveň důvěryhodnosti rovna nebo nižší než úroveň důvěryhodnosti sestavení, které generuje kód. Aby bylo možné tuto omezenou možnost přeskočit kontroly viditelnosti za běhu (JIT), přidá ReflectionPermission hostitelská aplikace do sady udělení objekt s příznakem ReflectionPermissionFlag.RestrictedMemberAccess (RMA).

Hostitel může například internetovým aplikacím udělit oprávnění k internetu plus RMA, aby internetová aplikace mohla generovat kód, který přistupuje k soukromý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í, internetová aplikace nemůže přistupovat ke č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 při vytváření anonymně hostovaných dynamických metod zahrnuty informace o zásobníku pro generující sestavení. Při vyvolání metody jsou kontrolovány informace zásobníku. Anonymně hostovaná dynamická metoda, která je vyvolána z plně důvěryhodného kódu, je tedy stále omezena na úroveň důvěryhodnosti vygenerovaného sestavení.

Vytvoření domény aplikace s částečným vztahem důvěryhodnosti a RMA

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

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

    Metoda AddPermission přidá oprávnění k sadě udělení, pokud ještě není zahrnuta. Pokud je oprávnění již zahrnuto v sadě udělení, přidají se zadané příznaky do stávajícího oprávnění.

    Poznámka

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

  2. Vytvořte doménu aplikace a zadejte informace o nastavení domény aplikace a sadu udělení.

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

Spouštění kódu v doménách aplikace v izolovaném prostoru (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ě a jak spustit její metody.

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

  1. Definujte třídu, která je odvozená z MarshalByRefObject. To vám umožní 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 vygeneruje 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 zobrazovaný název sestavení. Tento název se používá při vytváření instancí Worker třídy v doméně aplikace v izolovaném prostoru (sandbox).

    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 tohoto návodu. Do sady oprávnění nemusíte přidávat Internet žádná oprávnění, protože SimpleEmitDemo metoda používá pouze veřejné metody.

  5. V hlavním programu vytvořte instanci Worker třídy 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 tento kód použijete v sadě 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í SimpleEmitDemo metody . Volání je seřazeno přes hranice domény aplikace a kód se spustí v doméně aplikace v izolovaném prostoru (sandbox).

    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. Kód, který obsahují, je proto transparentní. Běžné dynamické metody na druhé straně musí být přidruženy k existujícímu modulu (ať už jsou přímo zadané nebo odvozené z přidruženého typu) a musí z daného modulu převzít úroveň zabezpečení.

Poznámka

Jediný způsob, 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. V sestavení anonymního hostování nelze explicitně zadat modul.

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ženy. Vzhledem k tomu, že anonymně hostované dynamické metody jsou izolované od jiného kódu, nemají přístup k soukromým datům. Mají však omezenou možnost přeskočit kontroly viditelnosti JIT, aby získaly přístup k soukromým datům. Tato možnost je omezena na sestavení, která mají úrovně důvěryhodnosti rovné nebo menší než úroveň důvěryhodnosti sestavení, které generuje kód.

Aby se zabránilo zvýšení oprávnění, jsou při vytváření anonymně hostovaných dynamických metod zahrnuty informace o zásobníku pro generující sestavení. Při vyvolání metody jsou kontrolovány informace 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 sestavení, které ji vygenerovalo.

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

  • Vytvořte anonymně hostované dynamické metody pomocí konstruktoru, který nespecifikuje přidružený modul nebo typ.

    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 anonymně hostovaná dynamická metoda používá pouze veřejné typy a metody, nevyžaduje omezený přístup člena a nemusí přeskočit kontroly viditelnosti JIT.

    K vygenerování dynamické metody se nevyžadují žádná zvláštní oprávnění, ale vygenerovaný kód vyžaduje oprávnění, která jsou požadována 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í nezahrnuje, vyvolá se při spuštění vygenerovaného kódu výjimka zabezpečení. Zde zobrazený kód vygeneruje 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ě můžete vytvořit anonymně hostované dynamické metody s omezenou možností přeskočit kontroly viditelnosti JIT pomocí konstruktoru DynamicMethod(String, Type, Type[], Boolean) a zadání true parametru 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 anonymně hostovaná dynamická metoda může přistupovat k privátním datům pouze v sestaveních s úrovní důvěryhodnosti, která je stejná nebo menší než úroveň důvěryhodnosti vygenerovaného sestavení. Pokud se například dynamická metoda spouští s důvěryhodností internetu, může přistupovat k privátním datům v jiných sestaveních, která se také spouští s důvěryhodností Internetu, ale nemůže přistupovat k privátním datům sestavení rozhraní .NET Framework. Sestavení rozhraní .NET Framework jsou nainstalována v globální mezipaměti sestavení (GPA) a jsou vždy plně důvěryhodná.

    Anonymně hostované dynamické metody můžou tuto omezenou možnost využít k přeskočení kontrol viditelnosti JIT pouze v případě, že hostitelská aplikace udělí příznak ReflectionPermissionReflectionPermissionFlag.RestrictedMemberAccess . Požadavek na toto oprávnění se provádí při vyvolání metody.

    Poznámka

    Informace o zásobníku volání pro generující sestavení jsou zahrnuty při vytváření dynamické metody. Proto je požadavek proveden proti oprávněním emitující sestavení místo sestavení, které volá 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ů. Jeho Worker třída zahrnuje metodu, která může vytvářet anonymně hostované dynamické metody s omezenou schopností nebo bez omezené možnosti přeskočit kontroly viditelnosti, a příklad ukazuje výsledek spuštění této metody v aplikačních doménách, které mají různé úrovně důvěryhodnosti.

    Poznámka

    Omezená možnost přeskočit kontroly viditelnosti je funkcí 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ěryhodnost.

Příklad

Description

Následující příklad kódu ukazuje použití příznaku RestrictedMemberAccess k povolení anonymně hostovaných dynamických metod přeskočit kontroly viditelnosti JIT, ale pouze v případě, že cílový člen má stejnou nebo nižší úroveň důvěryhodnosti než sestavení, které generuje kód.

Příklad definuje Worker třídu, která může být seřazena přes hranice domény aplikace. Třída má dvě AccessPrivateMethod přetížení metody, které generují a spouštějí dynamické metody. První přetížení vygeneruje dynamickou metodu, která volá privátní PrivateMethod metodu Worker třídy a může vygenerovat dynamickou metodu s kontrolami viditelnosti JIT nebo bez ní. Druhé přetížení vygeneruje dynamickou metodu internal , která přistupuje k vlastnosti (Friend vlastnost v jazyce Visual Basic) String třídy.

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

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

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

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

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

  • Provede se druhé přetížení AccessPrivateMethod metody a kontroly viditelnosti JIT se opět přeskočí. Tentokrát dynamická metoda selže při kompilaci, protože se pokusí o přístup k internalFirstChar vlastnosti String třídy. Sestavení, které obsahuje String třídu, 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ého částečně důvěryhodného kódu bez ohrožení zabezpečení 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("{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.
' 

Probíhá kompilace kódu

  • Pokud vytvoří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ž ji CreateInstanceAndUnwrap předáte metodě. Obor názvů je ve výchozím nastavení název projektu. Pokud je například projekt "PartialTrust", musí být název třídy "PartialTrust.Worker".

Viz také