Пошаговое руководство. Выпуск кода в сценариях частичного доверияWalkthrough: Emitting Code in Partial Trust Scenarios

При порождении отражения для полного или частичного доверия используется одинаковый набор интерфейсов API, но для некоторых функциональных возможностей требуются особые разрешения в коде с частичным доверием.Reflection emit uses the same API set in full or partial trust, but some features require special permissions in partially trusted code. Кроме того, в порождении отражения имеется функциональная возможность, анонимно размещенные динамические методы, которые предназначены для использования при частичном доверии и в прозрачных с точки зрения безопасности сборках.In addition, reflection emit has a feature, anonymously hosted dynamic methods, that is designed to be used with partial trust and by security-transparent assemblies.

Примечание

В версиях, предшествовавших .NET Framework 3.5, для порождения кода требовалось разрешение ReflectionPermission с флагом ReflectionPermissionFlag.ReflectionEmit.Before .NET Framework 3.5, emitting code required ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag. Это разрешение включено по умолчанию в именованные наборы разрешений FullTrust и Intranet, но отсутствует в наборе разрешений Internet.This permission is included by default in the FullTrust and Intranet named permission sets, but not in the Internet permission set. Поэтому библиотека может использоваться при частичном доверии, только если у нее был атрибут SecurityCriticalAttribute и она выполнила метод Assert для ReflectionEmit.Therefore, a library could be used from partial trust only if it had the SecurityCriticalAttribute attribute and also executed an Assert method for ReflectionEmit. Такие библиотеки требуют тщательной проверки безопасности, так как ошибки в коде могут стать причиной уязвимости.Such libraries require careful security review because coding errors could result in security holes. Платформа .NET Framework 3.5 позволяет создавать код в сценариях частичного доверия без предъявления каких-либо требований к безопасности, так как создание кода по сути не является привилегированной операцией.The .NET Framework 3.5 allows code to be emitted in partial trust scenarios without issuing any security demands, because generating code is not inherently a privileged operation. То есть созданный код имеет не больше разрешений, чем породившая его сборка.That is, the generated code has no more permissions than the assembly that emits it. Это позволяет библиотекам порождать код, прозрачный с точки зрения безопасности, и устраняет необходимость в подтверждении ReflectionEmit, что упрощает задачу написания безопасной библиотеки, так как тщательная проверка безопасности не нужна.This enables libraries that emit code to be security-transparent and removes the need to assert ReflectionEmit, so that writing a secure library does not require such a thorough security review.

В данном пошаговом руководстве рассмотрены следующие задачи:This walkthrough illustrates the following tasks:

Дополнительные сведения о порождении кода в сценариях с частичным доверием см. в разделе Вопросы безопасности в порождаемом отражении.For more information about emitting code in partial trust scenarios, see Security Issues in Reflection Emit.

Полный код, показанный в данных процедурах, см. в разделе Пример в конце этого руководства.For a complete listing of the code shown in these procedures, see the Example section at the end of this walkthrough.

Настройка расположений с частичным довериемSetting up Partially Trusted Locations

В следующих двух процедурах показано, как настроить расположения, из которых можно протестировать код с частичным доверием.The following two procedures show how to set up locations from which you can test code with partial trust.

  • В первой процедуре показано, как создать домен изолированного приложения, в котором код выполняется с интернет-доверием.The first procedure shows how to create a sandboxed application domain in which code is granted Internet permissions.

  • Во второй процедуре показано, как добавить ReflectionPermission с флагом ReflectionPermissionFlag.RestrictedMemberAccess в домен приложения с частичным доверием для разрешения доступа к конфиденциальным данным в сборках с тем же или меньшим доверием.The second procedure shows how to add ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag to a partially trusted application domain, to enable access to private data in assemblies of equal or lesser trust.

Создание доменов изолированных приложенийCreating Sandboxed Application Domains

Чтобы создать домен приложения, в котором сборки будут выполняться при частичном доверии, необходимо указать набор разрешений, которые должны быть предоставлены сборкам, используя перегрузку метода AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) для создания домена приложения.To create an application domain in which your assemblies run with partial trust, you must specify the set of permissions to be granted to the assemblies by using the AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain. Самым простым способом указания набора разрешений является получение именованного набора разрешений из политики безопасности.The easiest way to specify the grant set is to retrieve a named permission set from security policy.

В следующей процедуре создается домен изолированного приложения, в котором код будет выполняться при частичном доверии, для проверки сценариев, в которых порожденный код имеет доступ только к открытым членам открытых типов.The following procedure creates a sandboxed application domain that runs your code with partial trust, to test scenarios in which emitted code can access only public members of public types. В следующей процедуре показано, как добавить RestrictedMemberAccess для проверки сценариев, в которых порожденный код имеет доступ к закрытым типам и членам в сборках, которым предоставлены равнозначные или меньшие разрешения.A subsequent procedure shows how to add RestrictedMemberAccess, to test scenarios in which emitted code can access nonpublic types and members in assemblies that are granted equal or lesser permissions.

Создание домена приложения с частичным довериемTo create an application domain with partial trust

  1. Создайте набор разрешений, которые следует предоставить сборкам в домене изолированного приложения.Create a permission set to grant to the assemblies in the sandboxed application domain. В этом случае используется набор разрешений зоны Интернета.In this case, the permission set of the Internet zone is used.

    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. Создайте объект AppDomainSetup для инициализации домена приложения с помощью пути к приложению.Create an AppDomainSetup object to initialize the application domain with an application path.

    Важно!

    Для простоты в этом примере кода используется текущая папка.For simplicity, this code example uses the current folder. Для выполнения кода, поступившего из Интернета, используйте отдельную папку для ненадежного кода, как описано в разделе Практическое руководство. Выполнение не вполне безопасного кода в изолированной среде.To run code that actually comes from the Internet, use a separate folder for the untrusted code, as described in How to: Run Partially Trusted Code in a Sandbox.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Создайте домен приложения, указав сведения о настройке домена приложения и набор правил для всех сборок, выполняющихся в домене приложения.Create the application domain, specifying the application domain setup information and the grant set for all assemblies that execute in the application domain.

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

    С помощью последнего параметра перегрузки метода AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) можно указать набор сборок, которым будет предоставлено полное доверие, вместо набора правил для домена приложения.The last parameter of the AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload enables you to specify a set of assemblies that are to be granted full trust, instead of the grant set of the application domain. Вам не нужно указывать сборки .NET Framework, используемые приложением, так как они находятся в глобальном кэше сборок.You do not have to specify the .NET Framework assemblies that your application uses, because those assemblies are in the global assembly cache. Сборки, находящиеся в глобальном кэше сборок, всегда имеют полное доверие.Assemblies in the global assembly cache are always fully trusted. Этот параметр можно использовать для указания сборок со строгими именами, которые не находятся в глобальном кэше сборок.You can use this parameter to specify strong-named assemblies that are not in the global assembly cache.

Добавление RestrictedMemberAccess к изолированным доменамAdding RestrictedMemberAccess to Sandboxed Domains

Ведущие приложения могут разрешать доступ анонимно размещенных динамических методов к конфиденциальным данным в сборках, уровень доверия которых не превышает уровень доверия сборки, порождающей код.Host applications can allow anonymously hosted dynamic methods to have access to private data in assemblies that have trust levels equal to or less than the trust level of the assembly that emits the code. Чтобы разрешить эту ограниченную возможность пропуска проверок видимости, выполняемых JIT-компилятором, ведущее приложение добавляет объект ReflectionPermission с флагом ReflectionPermissionFlag.RestrictedMemberAccess (RMA) в набор правил.To enable this restricted ability to skip just-in-time (JIT) visibility checks, the host application adds a ReflectionPermission object with the ReflectionPermissionFlag.RestrictedMemberAccess (RMA) flag to the grant set.

Например, ведущее приложение может предоставить интернет-приложениям интернет-разрешения и RMA, так что интернет-приложение может породить код, который обращается к конфиденциальным данным в собственных сборках.For example, a host might grant Internet applications Internet permissions plus RMA, so that an Internet application can emit code that accesses private data in its own assemblies. Так как доступ ограничен сборками с таким же или меньшим доверием, веб-приложение не может обращаться к членам полностью доверенных сборок, например сборок .NET Framework.Because the access is limited to assemblies of equal or lesser trust, an Internet application cannot access members of fully trusted assemblies such as .NET Framework assemblies.

Примечание

Чтобы предотвратить повышение привилегий, при создании анонимно размещенных динамических методов включаются также сведения стека для порождающей сборки.To prevent elevation of privilege, stack information for the emitting assembly is included when anonymously hosted dynamic methods are constructed. При вызове метода проверяются сведения стека.When the method is invoked, the stack information is checked. Поэтому вызванный из полностью доверенного кода анонимно размещенный динамический метод все так же ограничен уровнем доверия порождающей сборки.Thus, an anonymously hosted dynamic method that is invoked from fully trusted code is still limited to the trust level of the emitting assembly.

Создание домена приложения с частичным доверием и RMATo create an application domain with partial trust plus RMA

  1. Создайте объект ReflectionPermission с флагом RestrictedMemberAccess (RMA) и используйте метод PermissionSet.SetPermission для добавления разрешения в набор правил.Create a new ReflectionPermission object with the RestrictedMemberAccess (RMA) flag, and use the PermissionSet.SetPermission method to add the permission to the grant set.

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

    Метод AddPermission добавляет это разрешение в набор правил, если его там еще нет.The AddPermission method adds the permission to the grant set if it is not already included. Если разрешение уже включено в набор правил, указанные флаги добавляются к существующим разрешениям.If the permission is already included in the grant set, the specified flags are added to the existing permission.

    Примечание

    RMA — это функциональная возможность анонимно размещенных динамических методов.RMA is a feature of anonymously hosted dynamic methods. Если обычные динамические методы пропускают проверки видимости, выполняемые JIT-компилятором, порождаемый код требует полного доверия.When ordinary dynamic methods skip JIT visibility checks, the emitted code requires full trust.

  2. Создайте домен приложения, указав сведения о настройке домена приложения и набор правил.Create the application domain, specifying the application domain setup information and the grant set.

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

Выполнение кода в доменах изолированных приложенийRunning Code in Sandboxed Application Domains

В следующей процедуре объясняется, как определить класс с помощью методов, которые могут быть выполнены в домене приложения, как создать экземпляр класса в домене и как выполнить его методы.The following procedure explains how to define a class by using methods that can be executed in an application domain, how to create an instance of the class in the domain, and how to execute its methods.

Определение и выполнение метода в домене приложенияTo define and execute a method in an application domain

  1. Определите класс, производный от класса MarshalByRefObject.Define a class that derives from MarshalByRefObject. Это позволит создавать экземпляры класса в других доменах приложений, а также вызывать методы за пределами домена приложения.This enables you to create instances of the class in other application domains and to make method calls across application domain boundaries. Класс в этом примере назван Worker.The class in this example is named Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Определите открытый метод, содержащий код, который следует выполнить.Define a public method that contains the code you want to execute. В этом примере в коде порождается простой динамический метод, создается делегат для выполнения этого метода и вызывается делегат.In this example, the code emits a simple dynamic method, creates a delegate to execute the method, and invokes the delegate.

    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. В основной программе получите отображаемое имя сборки.In your main program, get the display name of your assembly. Это имя используется при создании экземпляров класса Worker в домене изолированного приложения.This name is used when you create instances of the Worker class in the sandboxed application domain.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. В основной программе создайте домен изолированного приложения, как описано в первой процедуре этого пошагового руководства.In your main program, create a sandboxed application domain, as described in the first procedure in this walkthrough. Добавлять какие-либо разрешения в набор разрешений Internet не нужно, так как метод SimpleEmitDemo использует только открытые методы.You do not have to add any permissions to the Internet permission set, because the SimpleEmitDemo method uses only public methods.

  5. В основной программе создайте экземпляр класса Worker в домене изолированного приложения.In your main program, create an instance of the Worker class in the sandboxed application domain.

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

    Метод CreateInstanceAndUnwrap создает объект в целевом домене приложения и возвращает прокси, который может использоваться для вызова свойств и методов объекта.The CreateInstanceAndUnwrap method creates the object in the target application domain and returns a proxy that can be used to call the properties and methods of the object.

    Примечание

    При использовании этого кода в Visual Studio необходимо изменить имя класса для включения пространства имен.If you use this code in Visual Studio, you must change the name of the class to include the namespace. По умолчанию пространство имен носит имя проекта.By default, the namespace is the name of the project. Например, если проект называется PartialTrust, имя класса должно быть PartialTrust.Worker.For example, if the project is "PartialTrust", the class name must be "PartialTrust.Worker".

  6. Добавьте код для вызова метода SimpleEmitDemo.Add code to call the SimpleEmitDemo method. Вызов маршалируется за пределы домена приложения, а код выполняется в изолированном домене приложения.The call is marshaled across the application domain boundary, and the code is executed in the sandboxed application domain.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Использование анонимно размещенных динамических методовUsing Anonymously Hosted Dynamic Methods

Анонимно размещенные динамические методы связаны с прозрачной сборкой, предоставленной системой.Anonymously hosted dynamic methods are associated with a transparent assembly that is provided by the system. Поэтому содержащийся в них код является прозрачным.Therefore, the code they contain is transparent. С другой стороны, обычные динамические методы должны быть связаны с существующим модулем (указанным непосредственно или выведенным из связанного типа) и принимать от него уровень безопасности.Ordinary dynamic methods, on the other hand, must be associated with an existing module (whether directly specified or inferred from an associated type), and take their security level from that module.

Примечание

Единственный способ сопоставления динамического метода со сборкой, предоставляющей анонимное размещение, — это использование конструкторов, описанных в следующей процедуре.The only way to associate a dynamic method with the assembly that provides anonymous hosting is to use the constructors that are described in the following procedure. Невозможно явно указать модуль в анонимно размещающей сборке.You cannot explicitly specify a module in the anonymous hosting assembly.

Обычные динамические методы имеют доступ к внутренним членам модуля, с которым они связаны, или к закрытым членам типа, с которым они связаны.Ordinary dynamic methods have access to the internal members of the module they are associated with, or to the private members of the type they are associated with. Так как анонимно размещенные динамические методы изолированы от другого кода, они не имеют доступа к конфиденциальным данным.Because anonymously hosted dynamic methods are isolated from other code, they do not have access to private data. Но у них есть ограниченная возможность пропускать проверки видимости, выполняемые JIT-компилятором, для получения доступа к конфиденциальным данным.However, they do have a restricted ability to skip JIT visibility checks to gain access to private data. Эта возможность ограничивается сборками, уровень доверия которых не превышает уровень доверия сборки, породившей этот код.This ability is limited to assemblies that have trust levels equal to or less than the trust level of the assembly that emits the code.

Чтобы предотвратить повышение привилегий, при создании анонимно размещенных динамических методов включаются также сведения стека для порождающей сборки.To prevent elevation of privilege, stack information for the emitting assembly is included when anonymously hosted dynamic methods are constructed. При вызове метода проверяются сведения стека.When the method is invoked, the stack information is checked. Вызванный из полностью доверенного кода анонимно размещенный динамический метод все так же ограничен уровнем доверия породившей его сборки.An anonymously hosted dynamic method that is invoked from fully trusted code is still limited to the trust level of the assembly that emitted it.

Использование анонимно размещенных динамических методовTo use anonymously hosted dynamic methods

  • Создайте анонимно размещенный динамический метод с помощью конструктора, который не задает связанный модуль или тип.Create an anonymously hosted dynamic method by using a constructor that does not specify an associated module or type.

    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)
    

    Если анонимно размещенный динамический метод использует только открытые типы и методы, ему не требуется ограниченный доступ к членам и он может не пропускать проверки видимости, выполняемые JIT-компилятором.If an anonymously hosted dynamic method uses only public types and methods, it does not require restricted member access and does not have to skip JIT visibility checks.

    Специальных разрешений для порождения динамического метода не требуется, но порождаемый код нуждается в разрешениях, которые требуются для используемых в этом коде типов и методов.No special permissions are required to emit a dynamic method, but the emitted code requires the permissions that are demanded by the types and methods it uses. Например, если порожденный код вызывает метод, который получает доступ к файлу, необходимо разрешение FileIOPermission.For example, if the emitted code calls a method that accesses a file, it requires FileIOPermission. Если уровень доверия не включает это разрешение, при выполнении порожденного кода создается исключение безопасности.If the trust level does not include that permission, a security exception is thrown when the emitted code is executed. Приведенный здесь код порождает динамический метод, который использует только метод Console.WriteLine.The code shown here emits a dynamic method that uses only the Console.WriteLine method. Поэтому код может быть выполнен в расположениях с частичным доверием.Therefore, the code can be executed from partially trusted locations.

  • Кроме того, вы можете создать анонимно размещенный динамический метод с ограниченной возможностью пропуска проверок видимости, выполняемых JIT-компилятором, путем использования конструктора DynamicMethod(String, Type, Type[], Boolean) и указания значения true для параметра restrictedSkipVisibility.Alternatively, create an anonymously hosted dynamic method with restricted ability to skip JIT visibility checks, by using the DynamicMethod(String, Type, Type[], Boolean) constructor and specifying true for the restrictedSkipVisibility parameter.

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

    Ограничение заключается в том, что анонимно размещенный динамический метод может получать доступ к конфиденциальным данным только в сборках, уровень доверия которых не превышает уровень доверия порождающей сборки.The restriction is that the anonymously hosted dynamic method can access private data only in assemblies with trust levels equal to or less than the trust level of the emitting assembly. Например, если динамический метод выполняется с доверием Интернету, он может получить доступ к конфиденциальным данным в других сборках, которые также работают с доверием Интернету, но не может получить доступ к конфиденциальным данным сборок .NET Framework.For example, if the dynamic method is executing with Internet trust, it can access private data in other assemblies that are also executing with Internet trust, but it cannot access private data of .NET Framework assemblies. Сборки .NET framework устанавливаются в глобальном кэше сборок и всегда имеют полное доверие..NET Framework assemblies are installed in the global assembly cache and are always fully trusted.

    Анонимно размещенные динамические методы могут использовать эту ограниченную возможность пропуска проверок видимости, выполняемых JIT-компилятором, только в том случае, если ведущее приложение предоставляет разрешение ReflectionPermission с флагом ReflectionPermissionFlag.RestrictedMemberAccess.Anonymously hosted dynamic methods can use this restricted ability to skip JIT visibility checks only if the host application grants ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag. Это разрешение требуется при вызове метода.The demand for this permission is made when the method is invoked.

    Примечание

    Сведения стека вызовов для порождающей сборки включаются при создании динамического метода.Call stack information for the emitting assembly is included when the dynamic method is constructed. Поэтому запрос делается в отношении разрешений порождающей сборки, а не сборки, вызывающей метод.Therefore, the demand is made against the permissions of the emitting assembly instead of the assembly that invokes the method. Это препятствует выполнению порожденного кода с повышенным уровнем разрешений.This prevents the emitted code from being executed with elevated permissions.

    Полный пример кода в конце этого пошагового руководства служит для демонстрации использования ограниченного доступа к членам.The complete code example at the end of this walkthrough demonstrates the use and limitations of restricted member access. Класс Worker содержит метод, который может создавать анонимно размещенные динамические методы с ограниченной возможностью пропускать проверки видимости или без нее, а в примере показан результат выполнения этого метода в доменах приложений с другими уровнями доверия.Its Worker class includes a method that can create anonymously hosted dynamic methods with or without the restricted ability to skip visibility checks, and the example shows the result of executing this method in application domains that have different trust levels.

    Примечание

    Ограниченная возможность пропускать проверки видимости — это функциональная возможность анонимно размещенных динамических методов.The restricted ability to skip visibility checks is a feature of anonymously hosted dynamic methods. Если обычные динамические методы пропускают проверки видимости, выполняемые JIT-компилятором, им следует предоставить полное доверие.When ordinary dynamic methods skip JIT visibility checks, they must be granted full trust.

ПримерExample

ОписаниеDescription

В следующем примере кода демонстрируется использование флага RestrictedMemberAccess для разрешения пропуска проверок видимости, выполняемых JIT-компилятором, анонимно размещенными динамическими методами, но только в тех случаях, когда уровень доверия целевого члена не превышает уровень доверия сборки, порождающей код.The following code example demonstrates the use of the RestrictedMemberAccess flag to allow anonymously hosted dynamic methods to skip JIT visibility checks, but only when the target member is at an equal or lower level of trust than the assembly that emits the code.

В примере определяется класс Worker, который может маршалироваться через границы домена приложения.The example defines a Worker class that can be marshaled across application domain boundaries. Этот класс содержит две перегрузки метода AccessPrivateMethod, которые порождают и выполняют динамические методы.The class has two AccessPrivateMethod method overloads that emit and execute dynamic methods. Первая перегрузка порождает динамический метод, который вызывает закрытый метод PrivateMethod класса Worker. Она может порождать динамический метод с проверкой видимости с помощью JIT-компилятора или без нее.The first overload emits a dynamic method that calls the private PrivateMethod method of the Worker class, and it can emit the dynamic method with or without JIT visibility checks. Вторая перегрузка порождает динамический метод, который получает доступ к свойству internal (свойство Friend в Visual Basic) класса String.The second overload emits a dynamic method that accesses an internal property (Friend property in Visual Basic) of the String class.

В примере используется вспомогательный метод для создания набора правил, ограниченного разрешениями Internet, а затем создается домен приложения с помощью перегрузки метода AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) для указания необходимости использовать этот набор правил для всего кода, выполняемого в домене.The example uses a helper method to create a grant set limited to Internet permissions, and then creates an application domain, using the AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to specify that all code that executes in the domain uses this grant set. В примере создается экземпляр класса Worker в домене приложения, а затем дважды выполняется метод AccessPrivateMethod.The example creates an instance of the Worker class in the application domain, and executes the AccessPrivateMethod method two times.

  • При первом выполнении метода AccessPrivateMethod принудительно выполняются проверки видимости с помощью JIT-компилятора.The first time the AccessPrivateMethod method is executed, JIT visibility checks are enforced. Динамический метод завершается сбоем после вызова, так как проверки видимости с помощью JIT-компилятора не дают ему получить доступ к закрытому методу.The dynamic method fails when it is invoked, because JIT visibility checks prevent it from accessing the private method.

  • При втором выполнении метода AccessPrivateMethod проверки видимости с помощью JIT-компилятора пропускаются.The second time the AccessPrivateMethod method is executed, JIT visibility checks are skipped. Компиляция динамического метода завершается сбоем, так как набор правил Internet не предоставляет достаточных разрешений для пропуска проверок видимости.The dynamic method fails when it is compiled, because the Internet grant set does not grant sufficient permissions to skip visibility checks.

В примере в набор правил добавляется ReflectionPermission с ReflectionPermissionFlag.RestrictedMemberAccess.The example adds ReflectionPermission with ReflectionPermissionFlag.RestrictedMemberAccess to the grant set. Затем в примере создается второй домен и указывается, что весь код, выполняемый в домене, получает разрешения из нового набора правил.The example then creates a second domain, specifying that all code that executes in the domain is granted the permissions in the new grant set. В примере создается экземпляр класса Worker в новом домене приложения, а затем выполняются обе перегрузки метода AccessPrivateMethod.The example creates an instance of the Worker class in the new application domain, and executes both overloads of the AccessPrivateMethod method.

  • Выполняется первая перегрузка метода AccessPrivateMethod, и проверки видимости с помощью JIT-компилятора пропускаются.The first overload of the AccessPrivateMethod method is executed, and JIT visibility checks are skipped. Динамический метод успешно компилируется и выполняется, так как сборка, породившая код, является такой же, как сборка, содержащая закрытый метод.The dynamic method compiles and executes successfully, because the assembly that emits the code is the same as the assembly that contains the private method. Поэтому уровни доверия одинаковы.Therefore, the trust levels are equal. Если приложение, содержащее класс Worker, содержало бы несколько сборок, этот же процесс прошел бы успешно для любой из них, так как они все имели бы один и тот же уровень доверия.If the application that contains the Worker class had several assemblies, the same process would succeed for any one of those assemblies, because they would all be at the same trust level.

  • Выполняется вторая перегрузка метода AccessPrivateMethod, и проверки видимости с помощью JIT-компилятора снова пропускаются.The second overload of the AccessPrivateMethod method is executed, and again JIT visibility checks are skipped. На этот раз компиляция динамического метода завершается сбоем, потому что происходит попытка получить доступ к свойству internal FirstChar класса String.This time the dynamic method fails when it is compiled, because it tries to access the internal FirstChar property of the String class. Сборка, содержащая класс String, имеет полное доверие.The assembly that contains the String class is fully trusted. Поэтому уровень доверия выше, чем у сборки, порождающей код.Therefore, it is at a higher level of trust than the assembly that emits the code.

В этом сравнении показано, как ReflectionPermissionFlag.RestrictedMemberAccess позволяет пропускать в частично доверенном коде проверки видимости, предназначенные для другого частично доверенного кода, без нарушения безопасности доверенного кода.This comparison shows how ReflectionPermissionFlag.RestrictedMemberAccess enables partially trusted code to skip visibility checks for other partially trusted code without compromising the security of trusted code.

Код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.
' 

Компиляция кодаCompiling the Code

  • При сборке этого примера кода в Visual Studio необходимо изменить имя класса при передаче его в метод CreateInstanceAndUnwrap, включив в него пространство имен.If you build this code example in Visual Studio, you must change the name of the class to include the namespace when you pass it to the CreateInstanceAndUnwrap method. По умолчанию пространство имен носит имя проекта.By default, the namespace is the name of the project. Например, если проект называется PartialTrust, имя класса должно быть PartialTrust.Worker.For example, if the project is "PartialTrust", the class name must be "PartialTrust.Worker".

См. такжеSee also