Considerações sobre segurança relacionadas à reflexão

A reflexão fornece a capacidade de obter informações sobre tipos e membros e de acessar membros (ou seja, chamar métodos e construtores, obter e definir valores de propriedade, adicionar e remover manipuladores de eventos e assim por diante). O uso da reflexão para obter informações sobre tipos e membros não é restrito. Todo o código pode usar reflexões para realizar as seguintes tarefas:

  • Enumere os tipos e membros, e examine seus metadados.
  • Enumerar e examine os módulos e assemblies.

Usar reflexão para acessar membros está, por outro lado, sujeitos a restrições. A partir do .NET Framework 4, somente código confiável pode usar reflexão para acessar membros críticos para segurança. Além disso, somente o confiável pode usar reflexão para acessar membros não públicos que não estariam diretamente acessíveis em código compilado. Por fim, o código que usa reflexão para acessar um membro crítico para segurança deve ter as devidas permissões exigidas pelo membro crítico para segurança, assim como com código compilado.

O código pode usar reflexão para realizar os seguintes tipos de acesso, sujeito às permissões necessárias:

  • Acesse os membros públicos que não são críticos para segurança.

  • Acessar membros não públicos que estariam acessíveis ao código compilado, se tais membros não fossem críticos para segurança. Exemplos de tais membros não públicos:

    • Membros protegidos de classes base do código de chamada. (Na reflexão, isso é chamado de acesso de nível familiar.)

    • Membros internal (membros Friend no Visual Basic) no assembly do código de chamada. (Na reflexão, isso é chamado de acesso no nível do assembly.)

    • Membros privados de outras instâncias da classe que contém o código de chamada.

Por exemplo, o código que é executado em um domínio do aplicativo em área restrita é limitado ao acesso descrito nesta lista, a menos que o domínio do aplicativo conceda permissões adicionais.

A partir do .NET Framework 2.0 Service Pack 1, tentar acessar membros que normalmente não podem ser acessados gera uma demanda para o conjunto de concessões do objeto de destino mais ReflectionPermission com o sinalizador ReflectionPermissionFlag.MemberAccess. Código que está sendo executado com confiança total (por exemplo, o código em um aplicativo que é iniciado da linha de comando) sempre pode atender a essas permissões. (Isso é sujeito às limitações de acesso a membros de críticos para segurança, conforme descrito mais adiante neste artigo.)

Como opção, um domínio do aplicativo em área restrita pode conceder ReflectionPermission com o sinalizador ReflectionPermissionFlag.MemberAccess, conforme descrito na seção Acessando membros que são normalmente inacessíveis, mais adiante neste artigo.

Acessando membros críticos para segurança

Um membro é crítico para segurança se ele tiver o SecurityCriticalAttribute, se ele pertencer a um tipo que tem o SecurityCriticalAttribute ou se ele está em um assembly crítico para segurança. A partir do .NET Framework 4, as regras para acessar membros críticos para segurança são as seguintes:

  • O código transparente não pode usar reflexão para acessar membros críticos para segurança, mesmo que o código seja totalmente confiável. Um MethodAccessException, FieldAccessException ou TypeAccessException é gerado.

  • Código em execução com confiança parcial é tratado como transparente.

Essas regras são as mesmas se um membro crítico para segurança for acessado diretamente pelo código compilado ou por meio de reflexão.

Código de aplicativo que é executado da linha de comando é executado com confiança total. Desde que não esteja marcado como transparente, ele pode usar reflexão para acessar membros críticos para segurança. Quando o mesmo código é executado com confiança parcial (por exemplo, em um domínio do aplicativo em área restrita), o nível de confiança do assembly determina se ele pode acessar o código crítico para segurança: se o assembly tiver um nome forte e estiver instalado no cache de assembly global, ele é um assembly confiável e pode chamar membros crítico de segurança. Se não for confiável, ele se tornará transparente mesmo se não for marcado como transparente e não poderá acessar membros críticos para segurança.

Reflexão e transparência

Do .NET Framework 4 em diante, o Common Language Runtime determina o nível de transparência de um tipo ou membro de vários fatores, incluindo o nível de confiança do assembly e o nível de confiança do domínio do aplicativo. A reflexão fornece as propriedades IsSecurityCritical, IsSecuritySafeCritical e IsSecurityTransparent para que você possa descobrir o nível de transparência de um tipo. A tabela a seguir mostra as combinações válidas dessas propriedades.

Nível de segurança IsSecurityCritical IsSecuritySafeCritical IsSecurityTransparent
Crítico true false false
Crítico para segurança true true false
Transparente false false true

Usar essas propriedade é muito mais simples que examinar as anotações de segurança de um assembly e seus tipos, verificando o nível de confiança atual e tentando duplicar as regras do runtime. Por exemplo, o mesmo tipo pode ser crítico para segurança quando é executado da linha de comando ou transparente de segurança quando é executado em um domínio do aplicativo em área restrita.

Há propriedades semelhantes nas classes MethodBase, FieldInfo, TypeBuilder, MethodBuilder e DynamicMethod. (Para outras reflexão e abstrações de emissão de reflexão, os atributos de segurança são aplicados aos métodos associados; por exemplo, no caso de propriedades que são aplicadas aos acessadores de propriedade).

Acessando membros que são normalmente inacessíveis

Para usar a reflexão para invocar os membros que podem ser acessados de acordo com as regras de acessibilidade do Common Language Runtime, o código deve receber uma das duas permissões:

  • Para permitir que o código invoque qualquer membro não público: seu código deve receber a concessão de ReflectionPermission com o sinalizador ReflectionPermissionFlag.MemberAccess.

    Observação

    Por padrão, a política de segurança nega essa permissão para código originado da Internet. Essa permissão nunca deve ser concedida o código originado da Internet.

  • Para permitir que o código invoque qualquer membro não público, desde que o conjunto de concessões do assembly que contém o membro chamado seja o mesmo ou um subconjunto do conjunto de concessões do assembly que contém a invocação de código: seu código deve receber a concessão de ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess.

Por exemplo, suponha que você concedeu permissões da Internet a um domínio do aplicativo mais ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess e, em seguida, executou um aplicativo da Internet com dois assemblies, A e B.

  • O assembly A pode usar reflexão para acessar membros particulares do assembly B, pois o conjunto de concessões do assembly B não inclui permissões que não foram concedidas a A.

  • O assembly A não pode usar a reflexão para acessar membros particulares de assemblies do .NET Framework como mscorlib.dll, pois mscorlib.dll é totalmente confiável e, portanto, tem permissões que não foram concedidas ao assembly A. Um MemberAccessException é gerado quando a segurança de acesso do código percorre a pilha no tempo de execução.

Serialização

Para serialização, SecurityPermission com o sinalizador SecurityPermissionAttribute.SerializationFormatter fornece a capacidade de obter e definir os membros de tipos serializáveis, independentemente da acessibilidade. Essa permissão permite que o código descubra e altere o estado particular de uma instância. (Além de receber a concessão das permissões apropriadas, o tipo deve ser marcado como serializável nos metadados.)

Parâmetros do tipo MethodInfo

Evite escrever membros públicos que utilizam parâmetros MethodInfo, especialmente para código confiável. Esses membros podem ser mais vulneráveis a códigos mal-intencionados. Por exemplo, considere um membro público no código altamente confiável que utiliza um parâmetro MethodInfo. Suponha que o membro público chama indiretamente o método Invoke no parâmetro fornecido. Se o membro público não executa as verificações de permissão necessária, a chamada para o método Invoke sempre terá êxito, pois o sistema de segurança determina se o chamador é altamente confiável. Mesmo que o código mal-intencionado não tenha permissão para invocar o método indiretamente, ele ainda poderá fazer isso indiretamente chamando o membro público.

Informações sobre versão

  • A partir do .NET Framework 4, código transparente não pode usar reflexão para acessar membros críticos para segurança.

  • O sinalizador ReflectionPermissionFlag.RestrictedMemberAccess foi introduzido no .NET Framework 2.0 Service Pack 1. Versões anteriores do .NET Framework exigem o sinalizador ReflectionPermissionFlag.MemberAccess para o código que usa a reflexão para acessar membros não públicos. Esta é uma permissão que nunca deve ser concedida a código parcialmente confiável.

  • A partir do .NET Framework 2.0, usar reflexão para obter informações sobre tipos e membros não públicos não requer permissões. Em versões anteriores, o ReflectionPermission com o sinalizador ReflectionPermissionFlag.TypeInformation é obrigatório.

Confira também