Problemas de segurança na emissão de reflexão

O .NET Framework fornece três maneiras de emitir a MSIL (linguagem intermediária da Microsoft), cada uma com problemas de segurança inerentes:

Independentemente do modo como você gerar código dinâmico, a execução do código gerado requer que todas as permissões necessárias para os tipos e métodos que o código gerado usa.

Observação

As permissões necessárias para refletir no código e emitir código foram alteradas com as versões seguintes do .NET Framework. Consulte Informações de versão, mais adiante neste artigo.

Assemblies Dinâmicos

Os assemblies dinâmicos são criados usando as sobrecargas do método AppDomain.DefineDynamicAssembly. A maioria das sobrecargas desse método foi preterida no .NET Framework 4, devido à eliminação da política de segurança em todo o computador. As sobrecargas restantes podem ser executadas por qualquer código, independentemente do nível de confiança. Essas sobrecargas se enquadram em dois grupos: aquelas que especificam uma lista de atributos a ser aplicada ao assembly dinâmico quando ele é criado e aquelas que não. Se você não especificar o modelo de transparência do assembly, aplicando o atributo SecurityRulesAttribute quando criá-lo, o modelo de transparência será herdado do assembly emissor.

Observação

Os atributos aplicados ao assembly dinâmico após ele ser criado, usando o método SetCustomAttribute, não entram em vigor até que o assembly tenha sido salvo no disco e carregado na memória novamente.

O código em um assembly dinâmico pode acessar membros e tipos visíveis em outros assemblies.

Observação

Os assemblies dinâmicos não usam os sinalizadores ReflectionPermissionFlag.MemberAccess e ReflectionPermissionFlag.RestrictedMemberAccess que permitem que os métodos dinâmicos acessem tipos e membros não públicos.

Os assemblies dinâmicos transitórios são criados na memória e nunca salvos no disco, portanto, eles não exigem nenhuma permissão de acesso ao arquivo. Salvar um assembly dinâmico em disco requer FileIOPermission com os sinalizadores adequados.

Gerando assemblies dinâmicos do código parcialmente confiável

Considere as condições em que um assembly com permissões de Internet pode gerar um assembly dinâmico transitório e executar seu código:

  • O assembly dinâmico usa apenas tipos e membros públicos de outros assemblies.

  • As permissões exigidas por esses tipos e membros são incluídas no conjunto de concessão do assembly parcialmente confiável.

  • O assembly não é salvo no disco.

  • Os símbolos de depuração não são gerados. (Os conjuntos de permissões Internet e LocalIntranet não incluem as permissões necessárias.)

Métodos Dinâmicos Hospedados Anonimamente

Os métodos dinâmicos hospedados anonimamente são criados usando os dois construtores DynamicMethod que não especificam um módulo ou tipo associado, DynamicMethod(String, Type, Type[]) e DynamicMethod(String, Type, Type[], Boolean). Esses construtores colocam os métodos dinâmicos em um assembly transparente de segurança totalmente confiável fornecido pelo sistema. Não é necessária nenhuma permissão para usar esses construtores ou para emitir o código para os métodos dinâmicos.

Em vez disso, quando um método dinâmico hospedado anonimamente é criado, a pilha de chamadas é capturada. Quando o método é construído, as demandas de segurança são feitas em relação à pilha de chamadas capturada.

Observação

Conceitualmente, as demandas são feitas durante a construção do método. Ou seja, as demandas podem ser feitas conforme cada instrução MSIL é emitida. Na implementação atual, todas as solicitações são feitas quando o método DynamicMethod.CreateDelegate é chamado ou quando o compilador JIT (Just-In-Time) é invocado, se o método for invocado sem chamar CreateDelegate.

Se o domínio do aplicativo permitir isso, os métodos dinâmicos hospedados anonimamente podem ignorar as verificações de visibilidade JIT, sujeitos à seguinte restrição: os tipos e membros não públicos acessados por um método dinâmico hospedado anonimamente devem estar em assemblies cujos conjuntos de concessões sejam iguais ao, ou subconjuntos de, conjunto de concessões da pilha de chamadas emissora. Essa capacidade restrita de ignorar as verificações de visibilidade JIT é habilitada se o domínio do aplicativo concede ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess.

  • Se o método usar apenas membros e tipos públicos, não serão necessárias permissões durante a construção.

  • Se você especificar que as verificações de visibilidade JIT devem ser ignoradas, a solicitação feita quando o método é construído incluirá ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess e o conjunto de concessões do assembly que contém o membro não público sendo acessado.

Como o conjunto de concessões do membro não público é considerado, o código parcialmente confiável que recebeu ReflectionPermissionFlag.RestrictedMemberAccess não pode elevar seus privilégios executando membros não públicos de assemblies confiáveis.

Como com qualquer outro código emitido, executar o método dinâmico requer as permissões que são exigidas pelos métodos que o método dinâmico usa.

O assembly do sistema que hospeda os métodos dinâmicos hospedados anonimamente usa o modelo de transparência SecurityRuleSet.Level1, que era o modelo de transparência utilizado no .NET Framework antes do .NET Framework 4.

Para obter mais informações, consulte a classe DynamicMethod.

Gerando métodos dinâmicos hospedados anonimamente do código parcialmente confiável

Considere as condições em que um assembly com permissões de Internet pode gerar um assembly dinâmico hospedado anonimamente e executá-lo:

  • O método dinâmico usa apenas tipos e membros públicos. Se o seu conjunto de concessões inclui ReflectionPermissionFlag.RestrictedMemberAccess, ele pode usar membros e tipos não públicos de qualquer assembly cujo conjunto de concessões seja igual ao, ou um subconjunto do, conjunto de concessões do assembly emissor.

  • As permissões exigidas por todos os tipos e membros usados pelo método dinâmico são incluídas no conjunto de concessões do assembly parcialmente confiável.

Observação

Os métodos dinâmicos não têm suporte para símbolos de depuração.

Métodos Dinâmicos Associados a Assemblies Existentes

Para associar um método dinâmico a um tipo ou um módulo em um assembly existente, use qualquer um dos construtores DynamicMethod que especificam o módulo ou tipo associado. As permissões necessárias para chamar esses construtores variam, pois associar um método dinâmico a um módulo ou tipo existente fornece ao método dinâmico o acesso aos membros e tipos não públicos:

  • Um método dinâmico associado um tipo tem acesso a todos os membros desse tipo, mesmo membros privados e a todos os tipos e membros internos no assembly que contém o tipo associado.

  • Um método dinâmico que está associado um módulo tem acesso a todos os tipos e membros internal (Friend no Visual Basic, assembly nos metadados do Common Language Runtime) no módulo.

Além disso, você pode usar um construtor que especifica a capacidade de ignorar as verificações de visibilidade do compilador JIT. Fazer isso concede ao seu método dinâmico o acesso a todos os tipos e membros em todos os assemblies, independentemente do nível de acesso.

As permissões exigidas pelo construtor dependem de quanto acesso você decide conceder ao seu método dinâmico:

Embora os itens nessa lista estejam descritos em termos do conjunto de concessões do assembly emissor, lembre-se de que as exigências são feitas em relação à pilha de chamadas completa, incluindo o limite de domínio do aplicativo.

Para obter mais informações, consulte a classe DynamicMethod.

Gerando métodos dinâmicos do código parcialmente confiável

Observação

A maneira recomendada para gerar métodos dinâmicos a partir de um código parcialmente confiável é usando os métodos dinâmicos hospedados anonimamente.

Considere as condições em que um assembly com permissões de Internet pode gerar um método dinâmico e executá-lo:

  • O método dinâmico é associado ao módulo ou tipo que o emite ou seu conjunto de concessões inclui ReflectionPermissionFlag.RestrictedMemberAccess e ele é associado a um módulo em um assembly cujo conjunto de concessões é igual ao ou um subconjunto do, conjunto de concessões do assembly emissor.

  • O método dinâmico usa apenas tipos e membros públicos. Se seu conjunto de concessões incluir ReflectionPermissionFlag.RestrictedMemberAccess e estiver associado a um módulo em um assembly cujo conjunto de concessões é igual ao ou um subconjunto do, conjunto de concessões do assembly emissor, ele poderá usar tipos e membros marcados com internal (Friend no Visual Basic, assembly nos metadados do Common Language Runtime) no módulo associado.

  • As permissões exigidas por todos os tipos e membros usados pelo método dinâmico são incluídas no conjunto de concessões do assembly parcialmente confiável.

  • O método dinâmico não ignora as verificações de visibilidade JIT.

Observação

Os métodos dinâmicos não têm suporte para símbolos de depuração.

Informações sobre versão

A partir do .NET Framework 4, a política de segurança em todo o computador foi eliminada e a transparência de segurança passou a ser o mecanismo de imposição padrão.

A partir do .NET Framework 2.0 Service Pack 1, ReflectionPermission com o sinalizador ReflectionPermissionFlag.ReflectionEmit não é mais necessário ao emitir assemblies dinâmicos e métodos dinâmicos. Esse sinalizador é necessário em todas as versões anteriores do .NET Framework.

Observação

ReflectionPermission com o sinalizador ReflectionPermissionFlag.ReflectionEmit é incluído por padrão nos conjuntos de permissões denominados FullTrust e LocalIntranet, mas não no conjunto de permissões Internet. Portanto, em versões anteriores do .NET Framework, uma biblioteca poderá ser usada com permissões da Internet somente se executar um Assert para ReflectionEmit. Tais bibliotecas exigem uma análise atenta da segurança, pois erros de código poderiam resultar em falhas de segurança. O .NET Framework 2.0 SP1 permite que o código seja emitido em cenários de confiança parcial sem emitir nenhuma demanda de segurança, porque a geração de código não é inerentemente uma operação privilegiada. Ou seja, o código gerado não tem mais permissões que o assembly que o emite. Isso permite que as bibliotecas que emitem código tenham a segurança transparente e remove a necessidade de declarar ReflectionEmit, o que simplifica a tarefa de escrever uma biblioteca de segurança.

Além disso, o .NET Framework 2.0 SP1 introduz o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess para acessar os tipos e os membros não públicos de métodos dinâmicos parcialmente confiáveis. Versões anteriores do .NET Framework exigem o sinalizador ReflectionPermissionFlag.MemberAccess para os métodos dinâmicos que acessam os membros e tipos não públicos. Essa é uma permissão que não deve ser concedida nunca ao código parcialmente confiável.

Por fim, o .NET Framework 2.0 SP1 introduz os métodos hospedados anonimamente.

Obtendo informações sobre tipos e membros

A partir do .NET Framework 2.0, não são exigidas permissões para obter as informações sobre os tipos e membros não públicos. A reflexão é usada para obter as informações necessárias para emitir métodos dinâmicos. Por exemplo, os objetos MethodInfo são usados para emitir chamadas de método. Versões anteriores do .NET Framework exigem ReflectionPermission com o sinalizador ReflectionPermissionFlag.TypeInformation. Para obter mais informações, consulte Security Considerations for Reflection (Considerações sobre segurança relacionadas à reflexão).

Confira também