what reflexion programming por metodo invocar ejemplos java security design reflection

reflexion - what is reflection java



¿Cómo limitar setAccessible a solo usos "legítimos"? (3)

  • ¿Cuáles son los usos verdaderamente legítimos para setAccessible ?

Pruebas unitarias, partes internas de la JVM (por ejemplo, la implementación de System.setError(...) ) y así sucesivamente.

  • ¿Podría Java haberse diseñado para NO tener esta necesidad en primer lugar?
  • ¿Cuáles serían las consecuencias negativas (si las hay) de dicho diseño?

Muchas cosas no serían implementables. Por ejemplo, varias inyecciones de persistencia, serialización y dependencia de Java dependen de la reflexión. Y prácticamente todo lo que dependa de las convenciones de JavaBeans en tiempo de ejecución.

  • ¿Puedes restringir setAccessible a usos legítimos solamente?
  • ¿Es solo a través de SecurityManager ?

Sí.

  • ¿Como funciona? ¿Lista blanca / lista negra, granularidad, etc.?

Depende del permiso, pero creo que el permiso para usar setAccessible es binario. Si desea granularidad, necesita usar un cargador de clases diferente con un administrador de seguridad diferente para las clases que desee restringir. Supongo que podría implementar un administrador de seguridad personalizado que implemente una lógica granulada más fina.

  • ¿Es común tener que configurarlo en sus aplicaciones?

No.

  • ¿Puedo escribir mis clases para que sean configurables? ¿ setAccessible a setAccessible de SecurityManager configuración de SecurityManager ?
    • ¿O estoy a merced de quien maneja la configuración?

No, no puedes, y sí lo eres.

La otra alternativa es "hacer cumplir" esto a través de herramientas de análisis de código fuente; por ejemplo, reglas personalizadas de pmd o findbugs . O la revisión de código selectivo del código identificado por (digamos) grep setAccessible ...

En respuesta al seguimiento

Ninguna de mis clases tiene ninguna apariencia de privacidad exigible como tal. El patrón singleton (dejando de lado las dudas sobre sus méritos) ahora es imposible de aplicar.

Si eso te preocupa, entonces supongo que debes preocuparte. Pero realmente no deberías intentarlo puede obligar a otros programadores a respetar tus decisiones de diseño. Si son lo suficientemente estúpidos como para crear gratuitamente instancias múltiples de sus singletons (por ejemplo), pueden vivir con las consecuencias.

Y si quiere decir "privacidad" para abarcar el significado de proteger la información sensible de la divulgación, también está ladrando al árbol equivocado. La forma de proteger los datos confidenciales no es permitir que el código que no es de confianza entre en el entorno limitado de seguridad que trata con datos confidenciales. Los modificadores de acceso de Java no están destinados a ser un mecanismo de seguridad.

<Ejemplo de cadena> - ¿Soy el único que piensa que esto es una GRAN preocupación?

Probablemente no sea el único :-). Pero OMI, esto no es una preocupación. Es un hecho aceptado que el código que no es de confianza se debe ejecutar en una caja de arena. Si tiene un código de confianza / un programador de confianza que hace cosas como esta, entonces sus problemas son peores que tener cadenas inesperadamente mutables. (Piensa en bombas lógicas ...)

Cuanto más aprendí sobre el poder de java.lang.reflect.AccessibleObject.setAccessible , más me asombra lo que puede hacer. Esto se ha adaptado de mi respuesta a la pregunta ( Uso de la reflexión para cambiar el final estático File.separatorChar para la prueba unitaria ).

import java.lang.reflect.*; public class EverythingIsTrue { static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } public static void main(String args[]) throws Exception { setFinalStatic(Boolean.class.getField("FALSE"), true); System.out.format("Everything is %s", false); // "Everything is true" } }

Puedes hacer cosas realmente escandalosas:

public class UltimateAnswerToEverything { static Integer[] ultimateAnswer() { Integer[] ret = new Integer[256]; java.util.Arrays.fill(ret, 42); return ret; } public static void main(String args[]) throws Exception { EverythingIsTrue.setFinalStatic( Class.forName("java.lang.Integer$IntegerCache") .getDeclaredField("cache"), ultimateAnswer() ); System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42" } }

Es de suponer que los diseñadores de API se den cuenta de lo setAccessible puede ser el setAccessible , pero deben haber admitido que tiene usos legítimos para proporcionarlo. Entonces mis preguntas son:

  • ¿Cuáles son los usos verdaderamente legítimos para setAccessible ?
    • ¿Podría Java haberse diseñado para NO tener esta necesidad en primer lugar?
    • ¿Cuáles serían las consecuencias negativas (si las hay) de dicho diseño?
  • ¿Puedes restringir setAccessible a usos legítimos solamente?
    • ¿Es solo a través de SecurityManager ?
      • ¿Como funciona? ¿Lista blanca / lista negra, granularidad, etc.?
      • ¿Es común tener que configurarlo en sus aplicaciones?
    • ¿Puedo escribir mis clases para que sean configurables? ¿ setAccessible a setAccessible de SecurityManager configuración de SecurityManager ?
      • ¿O estoy a merced de quien maneja la configuración?

Supongo que una pregunta más importante es: ¿NECESITO PREOCUPARME POR ESTO?

Ninguna de mis clases tiene ninguna apariencia de privacidad exigible como tal. El patrón singleton (dejando de lado las dudas sobre sus méritos) ahora es imposible de aplicar. Como muestran mis fragmentos anteriores, incluso algunas suposiciones básicas de cómo funciona Java fundamental no están ni siquiera cerca de ser garantizadas.

¿ESTOS PROBLEMAS NO SON REALES?

De acuerdo, acabo de confirmar: gracias a setAccessible , las cadenas Java NO son inmutables.

import java.lang.reflect.*; public class MutableStrings { static void mutate(String s) throws Exception { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); value.set(s, s.toUpperCase().toCharArray()); } public static void main(String args[]) throws Exception { final String s = "Hello world!"; System.out.println(s); // "Hello world!" mutate(s); System.out.println(s); // "HELLO WORLD!" } }

¿Soy el único que piensa que esto es una GRAN preocupación?


La reflexión es ciertamente ortogonal a la seguridad bajo esta perspectiva.

¿Cómo podemos limitar la reflexión?

Java tiene Security Manager y ClassLoader como fundamentos de su modelo de seguridad. En tu caso, supongo que debes mirar java.lang.reflect.ReflectPermission .

Pero esto no resuelve por completo el problema de la reflexión. Las capacidades de reflexión que están disponibles deberían estar sujetas a un esquema de autorización detallado que no es el caso ahora. Por ejemplo, para permitir que cierto marco utilice la reflexión (por ejemplo, Hibernar), pero no el resto de su código. O para permitir que un programa se refleje solo de forma de solo lectura, con fines de depuración.

Un enfoque que puede convertirse en la corriente principal en el futuro es el uso de los llamados espejos para separar las capacidades reflexivas de las clases. Ver espejos: Principios de diseño para instalaciones de nivel meta . Sin embargo, hay varias otras investigaciones que abordan este problema. Pero estoy de acuerdo en que el problema es más severo para el lenguaje dinámico que los lenguajes estáticos.

¿Deberíamos estar preocupados por la superpotencia que nos brinda la reflexión? Si y no.

Sí, en el sentido de que se supone que la plataforma Java está asegurada con Classloader y el administrador de seguridad. La capacidad de meterse con la reflexión se puede ver como una brecha.

No, en el sentido de que la mayoría de los sistemas no son del todo seguros. Muchas clases se pueden subclasificar con frecuencia y es posible que ya abuses del sistema con eso. Por supuesto, las clases pueden final o sealed para que no puedan subclasificarse en otro jar. Pero solo unas pocas clases están aseguradas correctamente (por ejemplo, String) de acuerdo con esto.

Vea esta respuesta sobre la clase final para una buena explicación. Ver también el blog de Sami Koivu para más pirateo de java en torno a la seguridad.

El modelo de seguridad de Java puede considerarse insuficiente para algunos aspectos. Algunos lenguajes, como NewSpeak adoptan un enfoque aún más radical respecto de la modularidad, donde solo se tiene acceso a lo que explícitamente se le otorga mediante la inversión de la dependencia (por defecto, nada).

También es importante tener en cuenta que la seguridad es de todos modos relativa . En el nivel de idioma, por ejemplo, no se puede evitar que un formulario de módulo consuma el 100% de la CPU o consuma toda la memoria hasta una OutOfMemoryException . Tales preocupaciones deben abordarse por otros medios. Tal vez veamos en el futuro que Java se extienda con cuotas de utilización de recursos, pero no es para mañana :)

Podría ampliar más sobre el tema, pero creo que he hecho mi punto.


¿NECESITO PREOCUPARME POR ESTO?

Eso depende completamente de qué tipos de programas esté escribiendo y de qué tipo de arquitectura.

Si está distribuyendo un componente de software llamado foo.jar a las personas del mundo, de todos modos está completamente a su merced. Podrían modificar las definiciones de clase dentro de su .jar (mediante ingeniería inversa o manipulación directa de códigos de bytes). Podrían ejecutar su código en su propia JVM, etc. En este caso, preocuparse no servirá de nada.

Si está escribiendo una aplicación web que solo interactúa con personas y sistemas a través de HTTP y controla el servidor de aplicaciones, tampoco es una preocupación. Seguro que los codificadores compañeros en su empresa pueden crear código que rompe su patrón singleton, pero solo si realmente lo desean.

Si su trabajo futuro es escribir código en Sun Microsystems / Oracle y tiene la tarea de escribir código para el núcleo de Java u otros componentes confiables, es algo que debe tener en cuenta. Preocuparse, sin embargo, solo hará que pierdas tu cabello. En cualquier caso, es probable que le hagan leer las Pautas de codificación segura junto con la documentación interna.

Si vas a escribir applets de Java, el marco de seguridad es algo que debes tener en cuenta. Descubrirá que los applets sin firmar que intentan llamar a setAccessible resultarán en una SecurityException.

setAccessible no es lo único que rodea las comprobaciones de integridad convencionales. Hay una clase Java básica no API denominada sun.misc.Unsafe que puede hacer casi cualquier cosa que quiera, incluido el acceso directo a la memoria. El código nativo (JNI) también puede evitar este tipo de control.

En un entorno de espacio aislado (por ejemplo, Java Applets, JavaFX), cada clase tiene un conjunto de permisos y acceso a Inseguro, setAccessible y la definición de implementaciones nativas controladas por SecurityManager.

"Los modificadores de acceso a Java no pretenden ser un mecanismo de seguridad".

Eso depende mucho de dónde se está ejecutando el código de Java. Las clases principales de Java usan modificadores de acceso como un mecanismo de seguridad para aplicar el entorno limitado.

¿Cuáles son los usos verdaderamente legítimos para setAccessible?

Las clases principales de Java lo utilizan como una forma fácil de acceder a cosas que deben permanecer privadas por razones de seguridad. Como ejemplo, el marco de Serialización de Java lo usa para invocar constructores de objetos privados al deserializar objetos. Alguien mencionó System.setErr, y sería un buen ejemplo, pero curiosamente los métodos de clase del sistema setOut / setErr / setIn usan código nativo para establecer el valor del campo final.

Otro uso legítimo obvio son los marcos (persistencia, marcos web, inyección) que necesitan asomarse al interior de los objetos.

Los depuradores, en mi opinión, no entran en esta categoría, ya que normalmente no se ejecutan en el mismo proceso de JVM, sino que en su lugar utilizan la interfaz con la JVM utilizando otros medios (JPDA).

¿Podría Java haberse diseñado para NO tener esta necesidad en primer lugar?

Esa es una pregunta bastante profunda para responder bien. Me imagino que sí, pero necesitarías agregar algún otro mecanismo que no sea tan preferible.

¿Puedes restringir setAccessible a usos legítimos solamente?

La restricción más directa de OOTB que puede aplicar es tener un SecurityManager y permitir que setAccessible solo provenga de ciertas fuentes. Esto es lo que Java ya hace: las clases estándar de Java que provienen de su JAVA_HOME pueden hacer setAccessible, mientras que las clases de applet sin firma de foo.com no tienen permitido hacer setAccessible. Como se dijo anteriormente, este permiso es binario, en el sentido de que uno lo tiene o no. No hay una manera obvia de permitir que setAccessible modifique ciertos campos / métodos mientras no se permiten otros. Sin embargo, al usar SecurityManager, puede prohibir que las clases hagan referencia a ciertos paquetes por completo, con o sin reflexión.

¿Puedo escribir mis clases para configurarlas a prueba de acceso independientemente de la configuración de SecurityManager? ... ¿O estoy a merced de quien maneja la configuración?

No puedes y ciertamente lo eres.