Compartilhar via


Demonstra Passo a passo: Emitir código em cenários de confiança parcial

Emissão de reflexão usa a mesma API definido na relação de confiança total ou parcial, mas alguns recursos exigem permissões de acesso especiais em código parcialmente confiável.Além disso, emissão de reflexão possui um recurso, anonimamente hospedados métodos dinâmicos, que é projetado para ser usado com confiança parcial e por assemblies transparente de segurança.

Observação:

Antes de .NET Framework versão 3.5, emitindo o código necessário ReflectionPermission com o ReflectionPermissionFlag.ReflectionEmit sinalizar. Esta permissão é incluído por padrão no FullTrust e Intranet conjuntos de permissões nomeadas, mas não o Internet conjunto de permissões. Portanto, uma biblioteca poderia ser usada de confiança parcial apenas se tinha o SecurityCriticalAttribute atributo e também executado um Assert método para ReflectionEmit. Essas bibliotecas exigem revisão de segurança cuidadosa porque erros de código podem resultar em falhas de segurança. The .NET Framework 3,5 permite que o código ser emitido em cenários de confiança parcial sem emitir as demandas de segurança, como geração de código não é inerentemente uma operação privilegiada. Ou seja, o código gerado tem não mais permissões que o assembly que ela emite.Isso permite que bibliotecas que emitem código para ser transparente de segurança e remove a necessidade de declarar ReflectionEmit, para que escrever uma biblioteca segura não requer uma revisão de segurança completa.

Essa explicação passo a passo ilustra as seguintes tarefas:

  • configuração até ambientes parcialmente confiável para testar código.

  • Execução de código em domínios de aplicativo parcialmente confiável.

  • Usando anonimamente hospedado métodos dinâmicos para emitir e executar código em confiança parcial.

Para obter mais informações sobre o código de emissão em cenários de confiança parcial, consulte Problemas de segurança no reflexão Emit.

Para obter uma lista completa de código mostra esses procedimentos, consulte o Seção do exemplo no participante desta explicação passo a passo.

configuração até locais parcialmente confiável

Os procedimentos a seguir mostram como configurar locais de onde o código pode ser executado com confiança parcial.

  • O primeiro procedimento mostra como criar um domínio do aplicativo no modo seguro no qual o código é executado com confiança da Internet.Ela também explica uma armadilha comum.

  • O segundo procedimento mostra como adicionar ReflectionPermission com o ReflectionPermissionFlag.RestrictedMemberAccess sinalizar para o domínio do aplicativo parcialmente confiável, para permitir o acesso a dados particulares em módulos (assemblies) de confiança igual ou menor.

  • O procedimento a terceiro mostra como criar um agrupar de códigos que associa uma relação de confiança de nível com uma pasta, para que todos os assemblies localizados na pasta executar com confiança parcial.

Juntamente com esses procedimentos, em cenários simples, você pode usar um atributo de assembly, sistema autônomo a seguir para executar um assembly sem SkipVerification permissão. De maneira semelhante, você pode usar um atributo para recusar MemberAccess permissão.

<Assembly:SecurityPermissionAttribute(SecurityAction.RequestRefuse, Flags:=SecurityPermissionFlag.SkipVerification)>
[assembly:SecurityPermissionAttribute(SecurityAction.RequestRefuse, Flags=SecurityPermissionFlag.SkipVerification)]

Criando domínios de aplicativo no modo seguro

Para criar um domínio do aplicativo no qual seus assemblies são executados com confiança parcial, você deve especificar o conjunto de permissões seja concedido aos assemblies usando o AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) sobrecarga de método para criar o domínio do aplicativo. A maneira mais fácil para especificar o conjunto de concessão é recuperar um nomeado permissão defina de diretiva de segurança.

Cuidado:

Você não pode criar um domínio do aplicativo no modo seguro, especificando somente evidência .Você deve especificar um conjunto de concessão ou um domínio do aplicativo nível de diretiva .( Definir nível de diretiva de domínio um aplicativo é não discutidas neste tópico .) Por exemplo, se você usar o CreateDomain(String, Evidence) sobrecarga de método com evidência de Internet, as permissões são aplicadas somente em limites de domínio do aplicativo. Dentro do domínio do aplicativo, os assemblies recebem permissões concedidas com base na diretiva de segurança padrão.Para um aplicativo de console em seu computador, que seria confiança total.

O procedimento a seguir cria um domínio do aplicativo no modo seguro do que executa seu código com confiança parcial, a teste cenários em que o código emitido pode acessar somente os membros públicos da tipos públicos.Um procedimento subseqüente mostra como adicionar RestrictedMemberAccess, para testar cenários em que o código emitido pode acessar confidenciais tipos e membros em módulos (assemblies) que foram concedidas permissões iguais ou menor.

Para criar um domínio do aplicativo com confiança parcial

  1. Use a seguinte função auxiliar obter chamada permissão define da diretiva de segurança.

    Private Shared Function GetNamedPermissionSet(ByVal name As String) As PermissionSet 
    
        If (String.IsNullOrEmpty(name)) Then 
            Throw New ArgumentException("name", "Cannot search for a permission set without a name.")
        End If
    
        Dim foundName As Boolean = False
        Dim setIntersection As New PermissionSet(PermissionState.Unrestricted)
    
        ' Search all policy levels.
        Dim levelEnumerator As IEnumerator = SecurityManager.PolicyHierarchy()
        While (levelEnumerator.MoveNext())
    
            Dim level As PolicyLevel = levelEnumerator.Current 
            Debug.Assert(level IsNot Nothing)
    
            ' If this policy level has a named permission set with the 
            ' specified name, intersect it with previous levels.
            Dim levelSet As PermissionSet = level.GetNamedPermissionSet(name)
            If (levelSet IsNot Nothing) Then
    
                foundName = True
                setIntersection = setIntersection.Intersect(levelSet)
    
                ' Intersect() returns null for an empty set. If this occurs
                ' at any point, the resulting permission set is empty.
                If (setIntersection Is Nothing) Then
                    Return New PermissionSet(PermissionState.None)
                End If
            End If
        End While
    
        If Not foundName Then
            setIntersection = New PermissionSet(PermissionState.None)
        End If
        Return setIntersection
    
    End Function 
    
    private static PermissionSet GetNamedPermissionSet(string name)
    {
        if (String.IsNullOrEmpty(name))
            throw new ArgumentException("name", "Cannot search for a permission set without a name.");
    
        bool foundName = false;
        PermissionSet setIntersection = new PermissionSet(PermissionState.Unrestricted);
    
        // Search all policy levels.
        IEnumerator levelEnumerator = SecurityManager.PolicyHierarchy();
        while (levelEnumerator.MoveNext())
        {
            PolicyLevel level = levelEnumerator.Current as PolicyLevel;
            Debug.Assert(level != null);
    
            // If this policy level has a named permission set with the 
            // specified name, intersect it with previous levels.
            PermissionSet levelSet = level.GetNamedPermissionSet(name);
            if (levelSet != null)
            {
                foundName = true;
                setIntersection = setIntersection.Intersect(levelSet);
    
                // Intersect() returns null for an empty set. If this occurs
                // at any point, the resulting permission set is empty.
                if (setIntersection == null)
                    return new PermissionSet(PermissionState.None);
            }
        }
    
        if (!foundName)
            setIntersection = new PermissionSet(PermissionState.None);
    
        return setIntersection;
    }
    

    Um conjunto de concessão é a interseção entre o permissão conjuntos concedidos em todos os níveis de diretiva.Ou seja, uma permissão específica não é concedida a menos que é concedido em todos os níveis de diretiva.Portanto, a função auxiliar começa com uma concessão definido para confiança total e enumera os níveis da hierarquia de política, levando a interseção dessa concessão definido com o permissão conjunto definido para cada nível.

    Observação:

    Você pode criar conjuntos de concessão que contenham qualquer combinação de permissões usando o PermissionSet classe.

    O uso da função auxiliar é demonstrado posteriormente neste procedimento.

  2. criar provas para o local usando as zonas de segurança parcialmente confiável.Nesse caso, a zona da Internet é usada.

    Dim zoneEvidence() As Object = { New Zone(SecurityZone.Internet) }
    Dim internetZone As New Evidence(zoneEvidence, zoneEvidence)
    
    Object[] zoneEvidence = { new Zone(SecurityZone.Internet) };
    Evidence internetZone = new Evidence(zoneEvidence, zoneEvidence);
    
  3. criar an AppDomainSetup objeto para inicializar o domínio do aplicativo com um caminho de aplicativo. Este exemplo de código usa a pasta corrente.

    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
  4. Use a função auxiliar para recuperar o conjunto de permissões nomeadas da diretiva do sistema.

    Dim internetSet As PermissionSet = GetNamedPermissionSet("Internet")
    
    PermissionSet internetSet = GetNamedPermissionSet("Internet");
    
  5. Crie o domínio do aplicativo, especificando a evidência, as informações de configuração do domínio do aplicativo e o conjunto de concessão.

    Dim ad As AppDomain = AppDomain.CreateDomain("ChildDomain1", _
                                                 internetZone, _
                                                 adSetup, _
                                                 internetSet, _
                                                 Nothing)
    
    AppDomain ad = AppDomain.CreateDomain("ChildDomain1", 
                                          internetZone, 
                                          adSetup, 
                                          internetSet, 
                                          null);
    

    O último parâmetro do AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) sobrecarga de método permite que você especificar um conjunto de módulos (assemblies) que devem receber confiança total, em vez do conjunto de concessão do domínio do aplicativo. Não é necessário especificar o .NET Framework módulos (assemblies) que o aplicativo usa, porque os assemblies no cache de assembly global. Assemblies na cache de assembly global sempre são totalmente confiável.Você pode usar esse parâmetro para especificar assemblies fortes que não estão no cache global de assemblies.

Adicionando RestrictedMemberAccess a domínios em modo seguro

Aplicativos de host podem permitir que anonimamente hospedados métodos dinâmicos ter acesso a particular dados em assemblies que têm níveis iguais ou menor que o nível de confiança do assembly que emite o código de confiança.Para ativar essa habilidade ignorar just-in-time (JIT) visibilidade restrita verificações, o aplicativo host adiciona um ReflectionPermission objeto com o ReflectionPermissionFlag.RestrictedMemberAccess sinalizar (RMA) para o conjunto de concessão.

Por exemplo, um host pode conceder RMA, além de permissões de Internet de aplicativos de Internet para que um aplicativo da Internet pode emitir código que acessa dados particulares em seus próprios assemblies.sistema autônomo o acesso é limitado a assemblies de confiança igual ou menor, um aplicativo da Internet não pode acessar membros de assemblies totalmente confiável, sistema autônomo .NET Framework assemblies.

Observação:

Para impedir elevação de privilégio, informações de pilha para o assembly de emissão são incluídas quando hospedados anonimamente métodos dinâmicos são construído .Quando o método é chamado, as informações de pilha são verificadas.Assim, um n anonimamente hospedado método dinâmico que é chamado de código totalmente confiável é o nível de confiança do assembly emissão ainda limitado.

Para criar um domínio do aplicativo com confiança parcial, além de RMA

  1. Usar a função auxiliar para recuperar o Internet conjunto de permissão da diretiva de segurança nomeado.

    internetSet = GetNamedPermissionSet("Internet")
    
    internetSet = GetNamedPermissionSet("Internet");
    
  2. Criar um novo ReflectionPermission objeto com o RestrictedMemberAccess Sinalizar e usar o PermissionSet.SetPermission Para adicionar a permissão de concessão conjunto.

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

    The AddPermission método adiciona a permissão de concessão de conjunto se ele não ainda esteja incluído. Se a permissão já está incluída no conjunto de concessão, os sinalizadores especificados serão adicionados à permissão existente.

    Observação:

    RMA é um recurso de métodos dinâmicos anonimamente hospedados.Quando os métodos dinâmicos comuns ignorar verificações de visibilidade JIT, o código emitido deve receber ReflectionPermission com o ReflectionPermissionFlag.MemberAccess Sinalizar juntamente com o RestrictedMemberAccess sinalizador.

  3. Crie o domínio do aplicativo, especificando a evidência, as informações de configuração do domínio do aplicativo e o conjunto de concessão.

    ad = AppDomain.CreateDomain("ChildDomain2", _
                                internetZone, _
                                adSetup, _
                                internetSet, _
                                Nothing)
    
    ad = AppDomain.CreateDomain("ChildDomain2", 
                                internetZone, 
                                adSetup, 
                                internetSet, 
                                null);
    

Criando uma pasta com permissões restritas

O procedimento a seguir mostra como criar um agrupar de códigos que associa as permissões de Internet com uma pasta e como adicionar o RestrictedMemberAccess sinalizar na concessão conjunto para o código que execute a partir da pasta.

Para criar uma pasta que tenha permissões de Internet

  1. clicar Iniciar, point to Painel de controle, point to Ferramentas administrativase, em seguida, clicar Configuração do Microsoft .NET estrutura 3.5.Você deve ter privilégios de administrador do sistema para usar a ferramenta de configuração.

  2. No painel esquerdo, em Configuração do .NET estrutura 2.0, expandir Meu computador, Diretiva de segurança do Common Language tempo de execução, Máquina, Grupos de códigos, All_Code.

  3. No painel direito, clicar Adicionar um agrupar de códigos filho para executar o Assistente para criar agrupar de código.

  4. Nomeie o agrupar de códigos, sistema autônomo "Área de segurança da Internet" e, opcionalmente, uma descrição.Clique em Next.

  5. No escolher o tipo de condição para este agrupar de códigos lista, selecionar URL.No URL caixa, digite o caminho completo da pasta que você deseja usar e clicar Próximo.Por exemplo, você pode digitar o seguinte:

    file://c:/InternetSandbox/*
    
  6. selecionar Internet from the Usar existente permissão definido lista e, em seguida, clicar Próximo.

    Observação:

    Para especificar um conjunto de permissões nomeadas e um ReflectionPermission objeto com o RestrictedMemberAccess sinalizar, clicar Criar um novo conjunto de permissões e especificar a permissão personalizada definida por meio de um arquivo XML.

  7. clicar Concluir para criar o agrupar de códigos.

  8. Coloque os módulos que você deseja executar com confiança limitada na pasta que você especificou na etapa 5.

Executando o código nos domínios de aplicativo no modo seguro

O procedimento a seguir explica como definir uma classe usando métodos que podem ser executados em um domínio do aplicativo, como criar uma instância da classe do domínio e como executar seus métodos.

Para definir e executar um método em um domínio do aplicativo

  1. Definir uma classe que deriva de MarshalByRefObject. Isso permite que você para criar instâncias da classe em outros domínios de aplicativo e fazer chamadas de método nos limites do domínio do aplicativo.A classe neste exemplo é nomeada Worker.

    Public Class Worker
        Inherits MarshalByRefObject
    
    public class Worker : MarshalByRefObject
    {
    
  2. Defina um método público que contém o código que você deseja executar.Neste exemplo, o código emite um método dinâmico simples, um delegado para executar o método cria e invoca o delegado.

    Public Sub SimpleEmitDemo()
    
        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)
    
        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub
    
    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);
    
        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }
    
  3. No seu programa principal, obter o nome para exibição do seu assembly.Esse nome é usado quando você criar instâncias do Worker classe no domínio do aplicativo no modo seguro.

    Dim asmName As String = [Assembly].GetExecutingAssembly().FullName
    
    String asmName = Assembly.GetExecutingAssembly().FullName;
    
  4. No seu programa principal, crie um domínio do aplicativo no modo seguro, conforme descrito em o primeiro procedimento nesta explicação passo a passo.Não é necessário adicionar quaisquer permissões à Internet permissão definida, porque o SimpleEmitDemo método usa apenas métodos públicos.

  5. No seu programa principal, criar uma instância do Worker classe no domínio do aplicativo no modo seguro.

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

    The CreateInstanceAndUnwrap método cria o objeto no domínio do aplicativo de destino e retorna um proxy que pode ser usado para telefonar as propriedades e métodos do objeto.

    Observação:

    Se você usar esse código em Visual Studio, você deve alterar o nome da classe para incluir o espaço para nome. Por padrão, o espaço para nome é o nome do projeto a. Por exemplo, se o projeto for "PartialTrust", o nome de classe deve ser "PartialTrust.Worker".

  6. Adicione código para telefonar o SimpleEmitDemo método. A telefonar é empacotada em limites de domínio do aplicativo e o código é executado no domínio de aplicativo no modo seguro.

    w.SimpleEmitDemo()
    
    w.SimpleEmitDemo();
    

Usando anônimo Hosted métodos dinâmicos

Anonimamente hospedados métodos dinâmicos estão associados um assembly que é fornecido pelo sistema.Portanto, eles são isolados dos outros códigos.Métodos dinâmicos comuns, por Outros lado, devem ser associados a um módulo existente ou a um tipo.

Observação:

A única maneira de associar um método dinâmico com o assembly que fornece hostin anônimo g é usar os construtores que são descrito no procedimento a seguir.Não é possível explicitl y especificar um módulo no assembly hospedagem anônimo .

Métodos dinâmicos comuns tem acesso a membros internos do módulo são associados, ou para o particular membros do tipo estão associados.Como métodos dinâmicos anonimamente hospedados são isolados de Outros código, eles não tem acesso para particular dados.No entanto, elas têm uma capacidade restrita de ignorar verificações de visibilidade JIT para obter acesso a particular dados.Essa capacidade é limitada a assemblies que têm níveis de confiança iguais ou menor que o nível de confiança do assembly que emite o código.

Para impedir elevação de privilégio, informações de pilha para o assembly de emissão são incluídas quando hospedados anonimamente métodos dinâmicos são construídos.Quando o método é chamado, as informações de pilha são verificadas.Um método dinâmico anonimamente hospedado que é chamado a partir de código totalmente confiável é o nível de confiança do assembly emitido, ele ainda limitado.

Para usar anonimamente hospedado métodos dinâmicos

  • Crie um método dinâmico anonimamente hospedado usando um construtor que não especifica um tipo ou o módulo associado.

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

    Se um método dinâmico anonimamente hospedado usa apenas tipos públicos e métodos, ele não requer acesso de membro restrito e não tem verificações de visibilidade ignorar JIT.

    Nenhuma permissão especial é necessárias para emitir um método dinâmico, mas o código emitido requer as permissões que são exigidas pelos tipos e métodos que ele usa.Por exemplo, se o código emitido chama um método que acessa um arquivo, ele requer FileIOPermission. Se o nível de confiança não incluir essa permissão, uma exceção de segurança é lançada quando código emitido é executado.O código mostrado aqui emite um método dinâmico que usa apenas o Console.WriteLine método. Portanto, o código pode ser executado de locais parcialmente confiável.

  • Como alternativa, criar um método dinâmico anonimamente hospedado restrito capacidade de ignorar verificações de visibilidade JIT, usando o DynamicMethod(String, Type, array<Type[], Boolean) construtor e especificando true para o restrictedSkipVisibility parâmetro.

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

    A restrição é que pode acessar o método dinâmico anonimamente hospedado particular dados somente em assemblies com níveis de confiança iguais ou menor que o nível de confiança do assembly emissão.Por exemplo, se o método dinâmico está sendo executado com confiança da Internet, ele pode acessar dados particulares em outros módulos (assemblies) que também está em execução com confiança da Internet, mas não pode acessar dados particulares de .NET Framework assemblies. .NET Framework assemblies são instalados no cache global de assemblies e sempre são totalmente confiável.

    Anonimamente hospedados métodos dinâmicos podem usar essa capacidade restrita para pular verificações de visibilidade JIT somente se o aplicativo host concede ReflectionPermission com o ReflectionPermissionFlag.RestrictedMemberAccess sinalizar. A demanda por essa permissão é feita quando o método é invocado.

    Observação:

    Informações de pilha de chamadas para o assembly de emissão são incluídas quando o método dinâmico é construído .Portanto , a solicitação é feita em relação às permissões do assembly emissão em vez de o assembly que invoca o método.Isso impede que o código emitido sendo executada com permissões elevadas.

    The exemplo de código completo no participante desta explicação passo a passo demonstra o uso e limitações de acesso de membro restrito.Its Worker classe inclui um método que pode criar métodos dinâmicos anonimamente hospedados com ou sem a capacidade de ignorar verificações de visibilidade restrita e o exemplo mostra o resultado da execução deste método em domínios que têm níveis de confiança diferente.

    Observação:

    A r estricted capacidade de Ignorar a visibilidade verificações é um recurso de métodos dinâmicos anonimamente hospedados.Quando os métodos dinâmicos comuns ignorar verificações de visibilidade JIT, deve ser concedidas ReflectionPermission com o ReflectionPermissionFlag.MemberAccess sinalizar. Além disso, métodos dinâmicos comuns que acessam dados particulares em módulos (assemblies) Outros de emissão assembly deve ter um dos ReflectionPermission com o RestrictedMemberAccess sinalizar ou SecurityPermission com o SecurityPermissionFlag.ControlEvidence sinalizar.

Exemplo

Descrição

O exemplo de código a seguir demonstra o uso do RestrictedMemberAccess sinalizar para permitir anonimamente hospedado métodos dinâmicos para pular verificações de visibilidade JIT, mas somente quando o membro de destino estiver em um nível igual ou menor de confiança que o assembly que emite o código.

O exemplo define um Worker classe que pode ser empacotado nos limites do domínio do aplicativo. A classe tem duas AccessPrivateMethod sobrecargas de método que emitem e executar métodos dinâmicos. A primeira sobrecarga emite um método dinâmico que chama particular PrivateMethod método para o Worker classe e podem emitir o método dinâmico com ou sem as verificações de visibilidade JIT. A segunda sobrecarga emite um método dinâmico que acessa um internal propriedade)Friend propriedade no Visual Basic) dos String classe.

O exemplo utiliza um método auxiliar para obter o Internet permissão definido da diretiva de segurança e, em seguida, cria um domínio do aplicativo usando o AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, array<StrongName[]) Defina a sobrecarga de método para especificar que todo código que executa no domínio usa este Grant Number. O exemplo cria uma instância do Worker classe no domínio do aplicativo e executa o AccessPrivateMethod método duas vezes.

  • A primeira time o AccessPrivateMethod método for executado, verificações de visibilidade do JIT são impostas. O método dinâmico falhará quando ele é chamado, porque JIT visibilidade verificações impedir que acessem o método particular.

  • O segundo time o AccessPrivateMethod método for executado, verificações de visibilidade do JIT são ignoradas. O método dinâmico falhar quando ele é compilado, porque o Internet conceda o conjunto não concede permissões suficientes para ignorar as verificações de visibilidade.

O exemplo utiliza um método auxiliar para obter o Internet conceder o conjunto e adiciona ReflectionPermission com ReflectionPermissionFlag.RestrictedMemberAccess a concessão definido. O exemplo, em seguida, cria um segundo domínio, especificar que todo o código que executa no domínio recebe as permissões no novo conjunto de concessão.O exemplo cria uma instância do Worker classe do novo domínio do aplicativo e executa ambas sobrecargas da AccessPrivateMethod método.

  • A primeira sobrecarga do AccessPrivateMethod método é executado e verificações de visibilidade do JIT são ignoradas. O método dinâmico compila e executa com êxito, porque o assembly que emite o código é o mesmo que o assembly que contém o método particular.Portanto, os níveis de confiança são iguais.Se o aplicativo que contém o Worker classe teve vários assemblies, o mesmo processo seria bem-sucedida para qualquer um desses assemblies, pois eles todos estaria no mesmo nível de confiança.

  • A segunda sobrecarga do AccessPrivateMethod método é executado e novamente verificações de visibilidade do JIT são ignoradas. This time the dynamic method fails when it is compiled, because it tries to access the internal FirstChar property of the String class.O assembly que contém o String classe é totalmente confiável. Portanto, é em um nível mais alto de confiança que o assembly que emite o código.

Essa comparação mostra como ReflectionPermissionFlag.RestrictedMemberAccess permite parcialmente confiável código para ignorar visibilidade verifica se há outros códigos parcialmente confiáveis sem comprometer a segurança do código confiável.

Código

Imports System
Imports System.Reflection.Emit
Imports System.Reflection
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Collections
Imports System.Diagnostics

' This code example works properly only if it is run from a fully 
' trusted location, such as your local computer.

' Delegates used to execute the dynamic methods.
'
Public Delegate Sub Test(ByVal w As Worker) 
Public Delegate Sub Test1() 
Public Delegate Function Test2(ByVal instance As String) As Char 

' The Worker class must inherit MarshalByRefObject so that its public 
' methods can be invoked across application domain boundaries.
'
Public Class Worker
    Inherits MarshalByRefObject

    Private Sub PrivateMethod() 
        Console.WriteLine("Worker.PrivateMethod()")
    End Sub 

    Public Sub SimpleEmitDemo()

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

        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub

    ' This overload of AccessPrivateMethod emits a dynamic method and
    ' specifies whether to skip JIT visiblity checks. It creates a 
    ' delegate for the method and invokes the delegate. The dynamic 
    ' method calls a private method of the Worker class.
    Overloads Public Sub AccessPrivateMethod( _
                       ByVal restrictedSkipVisibility As Boolean) 

        ' Create an unnamed dynamic method that has no return type,
        ' takes one parameter of type Worker, and optionally skips JIT
        ' visiblity checks.
        Dim meth As New DynamicMethod("", _
                                      Nothing, _
                                      New Type() { GetType(Worker) }, _
                                      restrictedSkipVisibility)

        ' Get a MethodInfo for the private method.
        Dim pvtMeth As MethodInfo = GetType(Worker).GetMethod( _
            "PrivateMethod", _
            BindingFlags.NonPublic Or BindingFlags.Instance)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target instance, onto the
        ' execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test = CType(meth.CreateDelegate(GetType(Test)), Test)
            Try
                t(Me)
            Catch ex As Exception
                Console.WriteLine("{0} was thrown when the delegate was invoked.", _
                    ex.GetType().Name)
            End Try
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub 


    ' This overload of AccessPrivateMethod emits a dynamic method that takes
    ' a string and returns the first character, using a private field of the 
    ' String class. The dynamic method skips JIT visiblity checks.
    Overloads Public Sub AccessPrivateMethod() 

        Dim meth As New DynamicMethod("", _
                                      GetType(Char), _
                                      New Type() {GetType(String)}, _
                                      True)

        ' Get a MethodInfo for the 'get' accessor of the private property.
        Dim pi As PropertyInfo = GetType(String).GetProperty( _
            "FirstChar", _
            BindingFlags.NonPublic Or BindingFlags.Instance) 
        Dim pvtMeth As MethodInfo = pi.GetGetMethod(True)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target string, onto the
        ' execution stack, call the 'get' accessor to put the result onto 
        ' the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test2 = CType(meth.CreateDelegate(GetType(Test2)), Test2)
            Dim first As Char = t("Hello, World!")
            Console.WriteLine("{0} is the first character.", first)
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub 
End Class

Friend Class Example

    ' The entry point for the code example.
    Shared Sub Main() 

        ' Get the display name of the executing assembly, to use when
        ' creating objects to run code in application domains.
        Dim asmName As String = [Assembly].GetExecutingAssembly().FullName

        ' Create evidence for a partially trusted location and a setup object
        ' that specifies the current directory for the application directory.
        Dim zoneEvidence() As Object = { New Zone(SecurityZone.Internet) }
        Dim internetZone As New Evidence(zoneEvidence, zoneEvidence)
        Dim adSetup As New AppDomainSetup()
        adSetup.ApplicationBase = "."

        ' Retrieve the Internet grant set from system policy, and create 
        ' an application domain in which all code that executes is granted
        ' the permissions of an application run from the Internet.
        Dim internetSet As PermissionSet = GetNamedPermissionSet("Internet")
        Dim ad As AppDomain = AppDomain.CreateDomain("ChildDomain1", _
                                                     internetZone, _
                                                     adSetup, _
                                                     internetSet, _
                                                     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. Now create a grant set composed 
        ' of the permissions granted to an Internet application plus
        ' RestrictedMemberAccess, 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)
        internetSet = GetNamedPermissionSet("Internet")
        internetSet.SetPermission( _
            New ReflectionPermission( _
                ReflectionPermissionFlag.RestrictedMemberAccess))
        ad = AppDomain.CreateDomain("ChildDomain2", _
                                    internetZone, _
                                    adSetup, _
                                    internetSet, _
                                    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 


    ' This method retrieves a named permission set from security policy.
    ' The return value is the intersection of all permission sets with the
    ' given name, from all policy levels, or an empty permission set if the
    ' name is not found.
    Private Shared Function GetNamedPermissionSet(ByVal name As String) As PermissionSet 

        If (String.IsNullOrEmpty(name)) Then 
            Throw New ArgumentException("name", "Cannot search for a permission set without a name.")
        End If

        Dim foundName As Boolean = False
        Dim setIntersection As New PermissionSet(PermissionState.Unrestricted)

        ' Search all policy levels.
        Dim levelEnumerator As IEnumerator = SecurityManager.PolicyHierarchy()
        While (levelEnumerator.MoveNext())

            Dim level As PolicyLevel = levelEnumerator.Current 
            Debug.Assert(level IsNot Nothing)

            ' If this policy level has a named permission set with the 
            ' specified name, intersect it with previous levels.
            Dim levelSet As PermissionSet = level.GetNamedPermissionSet(name)
            If (levelSet IsNot Nothing) Then

                foundName = True
                setIntersection = setIntersection.Intersect(levelSet)

                ' Intersect() returns null for an empty set. If this occurs
                ' at any point, the resulting permission set is empty.
                If (setIntersection Is Nothing) Then
                    Return New PermissionSet(PermissionState.None)
                End If
            End If
        End While

        If Not foundName Then
            setIntersection = New PermissionSet(PermissionState.None)
        End If
        Return setIntersection

    End Function 

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 compiled.
'Worker.PrivateMethod()
'MethodAccessException was thrown when the delegate was compiled.
' 
using System;
using System.Reflection.Emit;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Collections;
using System.Diagnostics;

// This code example works properly only if it is run from a fully 
// trusted location, such as your local computer.

// Delegates used to execute the dynamic methods.
//
public delegate void Test(Worker w);
public delegate void Test1();
public delegate char Test2(String instance);

// The Worker class must inherit MarshalByRefObject so that its public 
// methods can be invoked across application domain boundaries.
//
public class Worker : MarshalByRefObject
{
    private void PrivateMethod()
    {
        Console.WriteLine("Worker.PrivateMethod()");
    }

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);

        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }

    // This overload of AccessPrivateMethod emits a dynamic method and
    // specifies whether to skip JIT visiblity checks. It creates a 
    // delegate for the method and invokes the delegate. The dynamic 
    // method calls a private method of the Worker class.
    public void AccessPrivateMethod(bool restrictedSkipVisibility) 
    {
        // Create an unnamed dynamic method that has no return type,
        // takes one parameter of type Worker, and optionally skips JIT
        // visiblity checks.
        DynamicMethod meth = new DynamicMethod(
            "", 
            null, 
            new Type[] { typeof(Worker) }, 
            restrictedSkipVisibility);

        // Get a MethodInfo for the private method.
        MethodInfo pvtMeth = typeof(Worker).GetMethod("PrivateMethod",
            BindingFlags.NonPublic | BindingFlags.Instance);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target instance, onto the
        // execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and 
        // invoke it. 
        try 
        {
            Test t = (Test) meth.CreateDelegate(typeof(Test));
            try 
            {
                t(this);
            }
            catch (Exception ex) 
            {
                Console.WriteLine("{0} was thrown when the delegate was invoked.", 
                    ex.GetType().Name);
            }
        } 
        catch (Exception ex) 
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.", 
                ex.GetType().Name);
        }
    }

    // This overload of AccessPrivateMethod emits a dynamic method that takes
    // a string and returns the first character, using a private field of the 
    // String class. The dynamic method skips JIT visiblity checks.
    public void AccessPrivateMethod() 
    {
        DynamicMethod meth = new DynamicMethod("",
                                               typeof(char), 
                                               new Type[] { typeof(String) }, 
                                               true);

        // Get a MethodInfo for the 'get' accessor of the private property.
        PropertyInfo pi = typeof(System.String).GetProperty(
            "FirstChar",
            BindingFlags.NonPublic | BindingFlags.Instance);
        MethodInfo pvtMeth = pi.GetGetMethod(true);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target string, onto the
        // execution stack, call the 'get' accessor to put the result onto 
        // the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and 
        // invoke it. 
        try 
        {
            Test2 t = (Test2) meth.CreateDelegate(typeof(Test2));
            char first = t("Hello, World!");
            Console.WriteLine("{0} is the first character.", first);
        } 
        catch (Exception ex) 
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.", 
                ex.GetType().Name);
        }
    }


    // The entry point for the code example.
    static void Main()
    {
        // Get the display name of the executing assembly, to use when
        // creating objects to run code in application domains.
        String asmName = Assembly.GetExecutingAssembly().FullName;

        // Create evidence for a partially trusted location and a setup object
        // that specifies the current directory for the application directory.
        Object[] zoneEvidence = { new Zone(SecurityZone.Internet) };
        Evidence internetZone = new Evidence(zoneEvidence, zoneEvidence);
        AppDomainSetup adSetup = new AppDomainSetup();
        adSetup.ApplicationBase = ".";

        // Retrieve the Internet grant set from system policy, and create 
        // an application domain in which all code that executes is granted
        // the permissions of an application run from the Internet.
        PermissionSet internetSet = GetNamedPermissionSet("Internet");
        AppDomain ad = AppDomain.CreateDomain("ChildDomain1", 
                                              internetZone, 
                                              adSetup, 
                                              internetSet, 
                                              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 compiled.
        w.AccessPrivateMethod(true);


        // Unload the application domain. Now create a grant set composed 
        // of the permissions granted to an Internet application plus
        // RestrictedMemberAccess, 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);
        internetSet = GetNamedPermissionSet("Internet");
        internetSet.SetPermission(
            new ReflectionPermission(
                ReflectionPermissionFlag.RestrictedMemberAccess));
        ad = AppDomain.CreateDomain("ChildDomain2", 
                                    internetZone, 
                                    adSetup, 
                                    internetSet, 
                                    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 method retrieves a named permission set from security policy.
    // The return value is the intersection of all permission sets with the
    // given name, from all policy levels, or an empty permission set if the
    // name is not found.
    private static PermissionSet GetNamedPermissionSet(string name)
    {
        if (String.IsNullOrEmpty(name))
            throw new ArgumentException("name", "Cannot search for a permission set without a name.");

        bool foundName = false;
        PermissionSet setIntersection = new PermissionSet(PermissionState.Unrestricted);

        // Search all policy levels.
        IEnumerator levelEnumerator = SecurityManager.PolicyHierarchy();
        while (levelEnumerator.MoveNext())
        {
            PolicyLevel level = levelEnumerator.Current as PolicyLevel;
            Debug.Assert(level != null);

            // If this policy level has a named permission set with the 
            // specified name, intersect it with previous levels.
            PermissionSet levelSet = level.GetNamedPermissionSet(name);
            if (levelSet != null)
            {
                foundName = true;
                setIntersection = setIntersection.Intersect(levelSet);

                // Intersect() returns null for an empty set. If this occurs
                // at any point, the resulting permission set is empty.
                if (setIntersection == null)
                    return new PermissionSet(PermissionState.None);
            }
        }

        if (!foundName)
            setIntersection = new PermissionSet(PermissionState.None);

        return setIntersection;
    }
}

/* This code example produces the following output:

Hello, World!
MethodAccessException was thrown when the delegate was invoked.
MethodAccessException was thrown when the delegate was compiled.
Worker.PrivateMethod()
MethodAccessException was thrown when the delegate was compiled.
 */

Compilando o código

  • Se você criar este exemplo de código em Visual Studio, você deve alterar o nome da classe para incluir o namespace quando você passar para o CreateInstanceAndUnwrap método. Por padrão, o espaço para nome é o nome do projeto a.Por exemplo, se o projeto for "PartialTrust", o nome de classe deve ser "PartialTrust.Worker".

Consulte também

Tarefas

Como: Executar código parcialmente confiável em uma área de segurança

Conceitos

Problemas de segurança no reflexão Emit