¿Cuál es el riesgo de seguridad de la reflexión de objetos?

Así que después de unas horas de solución a la limitación de Reflection que actualmente está inhabilitada en Google App Engine, me preguntaba si alguien podría ayudarme a entender por qué la reflexión de objetos puede ser una amenaza. ¿Es porque puedo inspeccionar las variables privadas de una clase o hay otras razones más profundas?

1 – La reflexión (como concepto) es de hecho ortogonal a la seguridad.

Hubo un gran énfasis en el diseño de Java para convertirlo en una plataforma segura, con tipeo estático , administrador de seguridad , uso disciplinado del cargador de clases y ninguna forma de atornillar punteros / memoria . Puedes leer la entrevista de James Gosling en Masterminds de la progtwigción , que es interesante al respecto.

Pero cuanto más poder reflexivo tengas, más difícil será garantizar que las cosas estén seguras como deberían. La reflexión derrota notablemente el tipado estático y puede conducir a errores en tiempo de ejecución.

Pero también pueden suceder cosas más sutiles. Por ejemplo, los cargadores de clase, que se pueden considerar como ganchos reflectantes en el sistema, no se diseñaron correctamente en la versión inicial de Java, lo que condujo a la posible sustitución de tipos. El artículo carga dinámica de clase en la JVM, por Gilad Bracha, es perspicaz sobre tales cuestiones.

La reflexión no se puede desactivar del todo; siempre es posible reflexionar sobre sus propios campos / métodos públicos. Sin embargo, se puede deshabilitar la reflexión sobre estructuras privadas con AccessibleObject.setAccessible , ya que rompe la encapsulación . Con acceso a campos privados, etc., es posible la inspección y modificación de datos internos. Puede conducir a varios exploits maliciosos , por ejemplo

  • strings ya no son inmutables y pueden cambiarse (ver esta pregunta )
  • puede revelar información sensible de objetos que no posee
  • … otras hazañas …

Finalmente, hay otro mecanismo que pone en peligro la seguridad, en particular sun.misc.Unsafe que da acceso directo a la memoria: los indicadores están de vuelta.

2 – Ahora, la pregunta es si la reflexión (en la práctica) conduce a tantos riesgos.

He leído el enlace señalado por @dbyrne, pero se trata principalmente de .net. Además, no sé exactamente qué está deshabilitado para la aplicación Google. ¿Es solo la ReflectPermission u otro permiso del administrador de seguridad? Un peligro es claramente tener acceso al sistema de archivos y perder el tiempo.

El problema del acceso a datos privados y la encapsulación de ruptura se puede argumentar en la práctica. Escribir código de seguridad es de hecho extremadamente difícil, e incluso sin cambiar el modificador de acceso puede subclasificar las clases de una manera inapropiada, a menos que sean final , o incluso mejores, selladas, y pasarlas por alto. Esto es, por ejemplo, contra lo que intenta proteger la copia defensiva .

La seguridad de tipo también se ve amenazada por el error de tiempo de ejecución debido a la bajada, por lo que también se puede argumentar este punto.

En un entorno compartido / alojado, la seguridad es relativa . En el nivel de idioma, por ejemplo, no se puede evitar que un formulario de módulo consum el 100% de la CPU o consum toda la memoria hasta una OutOfMemoryException . Estas preocupaciones deben abordarse por otros medios, generalmente en el nivel del sistema operativo, con virtualización y cuotas.

Entonces mi respuesta personal sería: la reflexión es un riesgo de seguridad, pero no tan grande en la práctica si se compara con otros vectores de ataque potenciales.

Una aplicación puede usar las API de reflexión de Java para acceder y actualizar campos, y ejecutar métodos que están prohibidos por las reglas normales de acceso / visibilidad de Java. Con un poco de ingenio, esto es suficiente para:

  • acceder a la información que se supone que está oculta,
  • Subvertir el entorno limitado de seguridad de Java para que pueda interferir con otras cosas que se ejecutan en la JVM, acceder a los archivos en la máquina local, y así sucesivamente.

En determinadas circunstancias, incluso podría permitir la inyección de código nativo malicioso.

En primer lugar, si no has instalado un SecurityManager , no estás seguro de todos modos.

En segundo lugar, la reflexión no abre agujeros significativos a menos que el setAccessible() esté habilitado y que esté sujeto a una comprobación de seguridad (regida por el permiso de reflexión setAccessChecks ). Sin eso, aunque pueda saber que existe el campo o método privado (aunque eso requiere el permiso de tiempo de ejecución de accessDeclaredMembers ) no puede hacer mucho con ese conocimiento. Su mejor apuesta para atacar podría ser trabajar con objetos serializados, pero eso es una bola entera de cera.

Tenga en cuenta también que escribir un administrador de seguridad seguro y un cargador de clases no es trivial. Lo mejor es dejarlos a otros si no estás aspirando al mega-gurú-dom (o, más probablemente, niveles vergonzosos de fracaso).

GAE es un entorno de alojamiento compartido y aloja archivos WAR de múltiples usuarios. Es muy probable que varios archivos WAR estén alojados en la misma JVM, porque generar un proceso por WAR es simplemente ridículo. Por lo tanto, la única forma de proteger cada archivo war es a través de un cargador de clases personalizado para cada archivo WAR.

Ahora, supongamos que la reflexión fue permitida. A continuación, puede recorrer la jerarquía del cargador de clases y enumerar las clases / métodos de los archivos WAR pertenecientes a diferentes usuarios. Obviamente, esa es una gran preocupación.

Una teoría mía es que Google está tratando de ocultar algo. Al deshabilitar Reflection, Google podría ocultar nombres de variables, llamadas a funciones e incluso una API completa. Si Google esconde algo así como una API, entonces la certeza no le dirá al respecto.

Sé con certeza que la Reflexión juega un papel muy importante en las pruebas de seguridad. Por ejemplo, puede generar automáticamente pruebas de Fuzz utilizando la reflexión. AxMan usa TypeLib para identificar todas las clases y sus llamadas a métodos que conforman un objeto COM. Usando esta información AxMan instanciará cada clase y llamará a cada método con permutaciones de cadenas largas y números grandes. SOAP Fuzzers realiza pruebas similares utilizando el archivo WSDL para la reflexión.