Problemas de seguridad en la emisión de la reflexión
Actualización: noviembre 2007
.NET Framework proporciona tres mecanismos para emitir el lenguaje intermedio de Microsoft (MSIL), cada uno con sus propios problemas de seguridad:
Ensamblados dinámicos
Métodos dinámicos hospedados de forma anónima
Métodos dinámicos asociados a ensamblados existentes
Con independencia del modo en que se genere el código dinámico, al ejecutar el código generado, es necesario disponer de los permisos requeridos por los tipos y métodos que el código generado utiliza.
Nota: |
---|
Los permisos requeridos para la reflexión en código y la emisión de código han ido cambiando en las sucesivas versiones de .NET Framework. Vea la sección Información de versiones más adelante en este mismo tema. |
Ensamblados dinámicos
Los ensamblados dinámicos se crean con las sobrecargas del método AppDomain.DefineDynamicAssembly. Los permisos que se requieren dependen de la sobrecarga que se utilice. Por ejemplo, las sobrecargas que proporcionan evidencias requieren el permiso SecurityPermission con el marcador SecurityPermissionFlag.ControlEvidence. Algunas sobrecargas no requieren ningún permiso y pueden llamarse desde un código que sólo tenga permisos de Internet.
El código de los ensamblados dinámicos puede obtener acceso a los tipos y miembros visibles de otros ensamblados.
Nota: |
---|
Los ensamblados dinámicos no utilizan los marcadores ReflectionPermissionFlag.MemberAccess y ReflectionPermissionFlag.RestrictedMemberAccess, que permiten a los miembros dinámicos obtener acceso a tipos y miembros no públicos. |
Para generar código con símbolos de depuración, es necesario el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.ReflectionEmit.
Los ensamblados dinámicos transitorios se crean en memoria y nunca se guardan en disco, de modo que no necesitan ningún permiso de acceso a archivos. Si los ensamblados dinámicos se guardaran en el disco, se necesitarían permisos FileIOPermission con los marcadores adecuados.
Generar ensamblados dinámicos a partir de código de confianza parcial
Considere las condiciones en las que un ensamblado con permisos de Internet puede generar un ensamblado dinámico transitorio y ejecutar su código:
El ensamblado dinámico sólo utiliza tipos y miembros públicos de otros ensamblados.
Los permisos exigidos por esos tipos y miembros están incluidos en el conjunto de permisos concedidos del ensamblado de confianza parcial.
La sobrecarga del método DefineDynamicAssembly que se utiliza para crear el ensamblado dinámico no requiere ningún permiso especial (es decir, no se proporciona ninguna evidencia, etc.).
El ensamblado no está guardado en el disco.
No se generan símbolos de depuración. (Los conjuntos de permisos de Internet y LocalIntranet no incluyen el marcador ReflectionPermissionFlag.ReflectionEmit).
Establecer los permisos de los ensamblados dinámicos
En la lista siguiente, el "emisor" es el ensamblado que genera el ensamblado dinámico.
Un emisor que tiene permisos SecurityPermission con el marcador SecurityPermissionFlag.ControlEvidence puede proporcionar la evidencia del código generado. Esta prueba se asigna a través de directivas para determinar los permisos concedidos.
Un emisor puede proporcionar una evidencia nula, en cuyo caso el ensamblado obtiene el conjunto de permisos del emisor. De este modo, se garantiza que el código generado no tiene más permisos que su emisor.
Si proporciona conjuntos de permisos con el marcador SecurityAction.RequestMinimum, SecurityAction.RequestOptional o SecurityAction.RequestRefuse, estos conjuntos de permisos no se utilizan hasta que el ensamblado se guarda en el disco y, a continuación, se carga desde el disco.
Una vez que el ensamblado dinámico se ha guardado en el disco, el ensamblado es tratado como cualquier otro ensamblado que se cargue desde el disco.
El código que generan los emisores de confianza parcial siempre se comprueba. Concretamente, el motor en tiempo en ejecución comprueba siempre el código que no tiene el permiso SecurityPermission con el marcador SecurityPermissionFlag.SkipVerification. Los emisores de plena confianza pueden omitir las comprobaciones o requerir que se compruebe el código generado.
Métodos dinámicos hospedados de forma anónima
Los métodos dinámicos hospedados de forma anónima se crean con dos constructores de DynamicMethod que no especifican ningún módulo o tipo asociado: DynamicMethod(String, Type, array<Type[]) y DynamicMethod(String, Type, array<Type[], Boolean). Estos constructores sitúan los métodos dinámicos en un ensamblado proporcionado por el sistema de plena confianza y transparente en seguridad. No es necesario ningún permiso para utilizar estos constructores o emitir código para los métodos dinámicos.
En su lugar, cuando se crea un método dinámico hospedado de forma anónima, se captura la pila de llamadas. Cuando se construye el método, las peticiones de seguridad se realizan en la pila de llamadas capturadas.
Nota: |
---|
Conceptualmente, las peticiones se realizan durante la construcción del método. Es decir, las peticiones pueden realizarse cada vez que se emite una instrucción de MSIL. En la implementación actual, todas las peticiones se realizan cuando se llama al método DynamicMethod.CreateDelegate o cuando se invoca el compilador Just-In-Time (JIT), si el método se invoca sin llamar a CreateDelegate. |
Los métodos dinámicos hospedados de forma anónima pueden omitir las comprobaciones de visibilidad JIT, con la restricción siguiente: los tipos y miembros no públicos a los que tienen acceso los métodos dinámicos hospedados de forma anónima deben estar en ensamblados cuyo conjunto de permisos concedidos sea igual que el conjunto de permisos concedidos de la pila de llamadas emisora (o un subconjunto de éste). Esta capacidad restringida para omitir las comprobaciones de visibilidad JIT requiere permisos ReflectionPermission con el marcador ReflectionPermissionFlag.RestrictedMemberAccess.
Si el método sólo utiliza tipos y miembros públicos, no se requiere ningún permiso durante la construcción.
Si especifica que deben omitirse las comprobaciones de visibilidad JIT, la petición que se realiza cuando el método se construye incluye el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.RestrictedMemberAccess y el conjunto de permisos concedidos del ensamblado que contiene el miembro no público al que se tiene acceso.
Dado que el conjunto de permisos concedidos del miembro no público se tiene en cuenta, el código de confianza parcial al que se le han concedido permisos ReflectionPermissionFlag.RestrictedMemberAccess no puede elevar sus privilegios ejecutando miembros no públicos de ensamblados de confianza.
Al igual que cualquier otro código emitido, al ejecutar el método dinámico, es necesario que los métodos que utiliza el método dinámico soliciten los permisos.
Para obtener más información, vea la clase DynamicMethod.
Generar métodos dinámicos hospedados de forma anónima desde código de confianza parcial
Considere las condiciones en las que un ensamblado con permisos de Internet puede generar y ejecutar un método dinámico hospedado de forma anónima:
El método dinámico sólo utiliza tipos y miembros públicos. Si su conjunto de permisos concedidos incluye ReflectionPermissionFlag.RestrictedMemberAccess, puede utilizar tipos y miembros no públicos de cualquier ensamblado cuyo conjunto de permisos concedidos sea igual al conjunto de permisos concedidos del ensamblado emisor (o un subconjunto de éste).
Los permisos requeridos por todos los tipos y miembros que utiliza el método dinámico están incluidos en el conjunto de permisos concedidos del ensamblado de confianza parcial.
Nota: |
---|
Los métodos dinámicos no admiten símbolos de depuración. |
Métodos dinámicos asociados a ensamblados existentes
Para asociar un método dinámico a un tipo o módulo de un ensamblado existente, utilice cualquiera de los constructores de DynamicMethod que especifican el tipo o módulo asociado. Los permisos requeridos para llamar a estos constructores varían, ya que al asociar un método dinámico con un tipo o módulo existente, el método dinámico obtiene acceso a tipos y miembros no públicos:
Un método dinámico que está asociado a un tipo tiene acceso a todos los miembros de ese tipo, incluidos los miembros privados, y a todos los tipos y miembros internos del ensamblado que contiene el tipo asociado.
Un método dinámico que está asociado a un módulo tiene acceso a todos los tipos y miembros internal (Friend en Visual Basic, assembly en los metadatos de Common Language Runtime) del módulo.
Además, puede utilizar un constructor que establezca la capacidad de omitir las comprobaciones de visibilidad del compilador JIT. De esto modo, el método dinámico obtendrá acceso a todos los tipos y miembros de todos los ensamblados, con independencia del nivel de acceso.
Los permisos exigidos por el constructor dependen del nivel de acceso que decida conceder al método dinámico:
Si su método sólo utiliza tipos y miembros públicos y lo asocia a un tipo o un módulo propio, no se requiere ningún permiso.
Si especifica que las comprobaciones de visibilidad JIT deben omitirse, el constructor exige el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.MemberAccess.
Si asocia el método dinámico a otro tipo, incluso a otro tipo de su propio ensamblado, el constructor exige el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.MemberAccess y el permiso SecurityPermission con el marcador SecurityPermissionFlag.ControlEvidence.
Si asocia el método dinámico a un tipo o módulo de otro ensamblado, el constructor exige dos cosas: el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.RestrictedMemberAccess y el conjunto de permisos concedidos del ensamblado que contiene el otro módulo. Es decir, la pila de llamadas debe incluir todos los permisos del conjunto de permisos concedidos del módulo de destino, además del marcador ReflectionPermissionFlag.RestrictedMemberAccess.
Nota: A efectos de compatibilidad con versiones anteriores, si la petición del conjunto de permisos concedidos junto con el marcador ReflectionPermissionFlag.RestrictedMemberAccess no se realiza correctamente, el constructor exige el permiso SecurityPermission con el marcador SecurityPermissionFlag.ControlEvidence.
Aunque los elementos de esta lista se describen en función del conjunto de permisos concedidos del ensamblado emisor, recuerde que las peticiones se realizan en la pila de llamadas completa, incluido el límite del dominio de aplicación.
Para obtener más información, vea la clase DynamicMethod.
Generar métodos dinámicos desde código de confianza parcial
Nota: |
---|
La manera recomendada de generar los métodos dinámicos desde código de confianza parcial es utilizar métodos dinámicos hospedados de forma anónima. |
Considere las condiciones en las que un ensamblado con permisos de Internet puede generar un método dinámico y ejecutarlo:
O bien el método dinámico está asociado al módulo o al tipo que lo emite o bien su conjunto de permisos concedidos incluye ReflectionPermissionFlag.RestrictedMemberAccess y está asociado a un módulo de un ensamblado cuyo conjunto de permisos concedidos es igual que el conjunto de permisos concedidos del ensamblado emisor (o un subconjunto de éste).
El método dinámico sólo utiliza tipos y miembros públicos. Si su conjunto de permisos concedidos incluye ReflectionPermissionFlag.RestrictedMemberAccess y está asociado con un módulo de un ensamblado cuyo conjunto de permisos concedidos es igual al conjunto de permisos concedidos del ensamblado emisor (a un subconjunto de éste), puede usar los tipos y miembros marcados como internal (Friend en Visual Basic, assembly en los metadatos de Common Language Runtime) del módulo asociado.
Los permisos requeridos por todos los tipos y miembros que utiliza el método dinámico están incluidos en el conjunto de permisos concedidos del ensamblado de confianza parcial.
El método dinámico no omite las comprobaciones de visibilidad JIT.
Nota: |
---|
Los métodos dinámicos no admiten símbolos de depuración. |
Información de versiones
Ya no es necesario empezar por el permiso .NET Framework versión 2.0 Service Pack 1, ReflectionPermission con el marcador ReflectionPermissionFlag.ReflectionEmit cuando se emiten ensamblados y métodos dinámicos. Este marcador se requiere en todas las versiones anteriores de .NET Framework.
Nota: |
---|
El permiso ReflectionPermission con el marcador ReflectionPermissionFlag.ReflectionEmit está incluido de forma predeterminada en el conjunto de permisos con nombre FullTrust y LocalIntranet, pero no en el conjunto de permisos Internet. Por consiguiente, en versiones anteriores de .NET Framework, una biblioteca únicamente se puede utilizar con permisos de Internet si ejecuta un permiso Assert para ReflectionEmit. Estas bibliotecas requieren una revisión cuidadosa de la seguridad porque los errores de codificación pueden provocar carencias de seguridad. .NET Framework 2.0 SP1 permite emitir el código en escenarios de confianza parcial sin emitir ninguna petición de seguridad, porque la generación de código no es en sí una operación de privilegio. Es decir, el código generado no tiene más permisos que el ensamblado que lo emite. Esto permite que bibliotecas que emiten código sean transparentes en seguridad y elimina la necesidad de validar ReflectionEmit, lo que simplifica la tarea de escribir una biblioteca segura. |
Además, .NET Framework 2.0 SP1 introduce el marcador ReflectionPermissionFlag.RestrictedMemberAccess para obtener acceso a los tipos y miembros no públicos de los métodos dinámicos de confianza parcial. Las versiones anteriores de .NET Framework requieren el marcador ReflectionPermissionFlag.MemberAccess para los métodos dinámicos que tienen acceso a tipos y miembros no públicos; éste es un permiso que nunca debería concederse al código de confianza parcial.
Finalmente, .NET Framework 2.0 SP1 introduce los métodos hospedados de forma anónima.
Para usar estas características, el destino de la aplicación debe ser .NET Framework versión 3.5. Para obtener más información, vea Arquitectura de .NET Framework 3.5.
Obtener información de los tipos y miembros
A partir de .NET Framework 2.0, no se requieren permisos para obtener información sobre los tipos y miembros no públicos. La reflexión se utiliza a la hora de obtener la información necesaria para emitir métodos dinámicos. Por ejemplo, los objetos MethodInfo se utilizan para emitir llamadas a métodos. Las versiones anteriores de .NET Framework requieren el permiso ReflectionPermission con el marcador ReflectionPermissionFlag.TypeInformation. Para obtener más información, vea Consideraciones de seguridad sobre la reflexión.
Vea también
Conceptos
Consideraciones de seguridad sobre la reflexión