¿Por qué la matriz final estática pública es un agujero de seguridad?

Java eficaz dice:

// ¡Posible agujero de seguridad!

Cosa final pública estática [] VALORES = {…};

¿Alguien puede decirme qué es el agujero de seguridad?

La statement de campos static final public suele ser el sello distintivo de una constante de clase. Está perfectamente bien para tipos primitivos (ints, dobles, etc.), y clases inmutables, como cadenas y java.awt.Color . Con las matrices, el problema es que aunque la referencia de la matriz es constante, los elementos de la matriz aún se pueden cambiar, y como es un campo, los cambios no están protegidos, son incontrolados y, por lo general, no son bienvenidos.

Para combatir esto, la visibilidad del campo de la matriz se puede restringir a privado o privado de paquete, de modo que tenga un cuerpo de código más pequeño para considerar cuando busque una modificación sospechosa. Alternativamente, ya menudo es mejor eliminar la matriz y utilizar una “Lista” u otro tipo de colección apropiado. Al usar una colección, usted controla si se permiten las actualizaciones, ya que todas las actualizaciones pasan por los métodos. Puede evitar las actualizaciones envolviendo su colección usando Collections.unmodifiableList() . Pero tenga en cuenta que, aunque la colección sea inmutable, también debe asegurarse de que los tipos almacenados en ella también sean inmutables, o el riesgo de cambios no solicitados en una supuesta constante volverá a aparecer.

Para comprender por qué este es un agujero de seguridad potencial y no solo una encapsulación deficiente, considere el siguiente ejemplo:

 public class SafeSites { // a trusted class with permission to create network connections public static final String[] ALLOWED_URLS = new String[] { "http://amazon.com", "http://cnn.com"}; // this method allows untrusted code to connect to allowed sites (only) public static void doRequest(String url) { for (String allowed : ALLOWED_URLS) { if (url.equals(allowed)) { // send a request ... } } } } public class Untrusted { // An untrusted class that is executed in a security sandbox. public void naughtyBoy() { SafeSites.ALLOWED_URLS[0] = "http://myporn.com"; SafeSites.doRequest("http://myporn.com"); } } 

Como puede ver, el uso erróneo de una matriz final significa que un código no confiable puede subvertir la restricción que el código de confianza / zona de pruebas está intentando imponer. En este caso, esto es claramente un problema de seguridad.

Si su código no forma parte de una aplicación de seguridad crítica, entonces podría ignorar este problema. Pero IMO esto es una mala idea. En algún momento en el futuro, usted (u otra persona) puede reutilizar su código en un contexto donde la seguridad es una preocupación. En cualquier caso, esta es la razón por la que el autor considera que las matrices finales públicas son un problema de seguridad.


Amber dijo esto en un comentario:

No sería más un agujero de seguridad que privado si pudiera leer el código fuente y / o el código de bytes de cualquier manera …

Esto no es verdad.

El hecho de que un “tipo malo” pueda usar el código fuente / códigos de bytes para determinar que existe un private y se refiera a una matriz no es suficiente para romper la seguridad. El malo también tiene que inyectar código en una JVM que tenga los permisos necesarios para usar la reflexión. Este permiso no está disponible para código no confiable que se ejecuta en un entorno limitado de seguridad (implementado correctamente).

Tenga en cuenta que una matriz de longitud no nula siempre es mutable, por lo que es incorrecto que una clase tenga un campo de matriz final estática pública o un elemento de acceso que devuelva dicho campo. Si una clase tiene dicho campo o elemento de acceso, los clientes podrán modificar el contenido de la matriz.

Java efectiva , 2ª ed. (página 70)

Una clase externa puede modificar el contenido de la matriz, que probablemente no sea lo que usted quiere que hagan los usuarios de su clase (desea que lo hagan a través de un método). Parece que el autor quiso decir que viola la encapsulación, y no la seguridad.

Supongo que alguien que declara esta línea podría pensar que otras clases no pueden modificar el contenido de la matriz, ya que está marcado como final, pero esto no es cierto, la final solo le impide reasignar el atributo.

En esta statement, un cliente puede modificar Cosa [0], Cosa [1], etc. (es decir, elementos de la matriz).

Piensa que solo significa todo lo público vs lo privado. Se supone que es una buena práctica tener variables locales declaradas privadas, luego usar los métodos de obtención y configuración, en lugar de acceder a ellas directamente. Los hace un poco más difíciles para meterse fuera de su progtwig. Sobre esto, por lo que yo sé.

Porque, la palabra clave final asegura solo el valor de referencia (supongalo como ubicación de memoria, por ejemplo) pero no el contenido en ella.

También agregaría lo que Joshua Bloch propuso en Effective Java 3rd edition. Por supuesto, podemos cambiar fácilmente el valor de la matriz si se declara como:

 public static final String[] VALUES = { "a", "b" }; a.VALUES[0] = "changed value on index 0"; System.out.println(String.format("Result: %s", a.VALUES[0])); 

y obtenemos Result: changed value on index 0

Joshua Bloch propuso devolver copia de la matriz:

 private static final String[] VALUES = { "a", "b" }; public static final String[] values() { return VALUES.clone(); } 

así que ahora cuando intentamos:

 a.values()[0] = "changed value on index 0"; System.out.println(String.format("Result: %s", a.values()[0])); 

Obtenemos el Result: a eso es lo que queríamos lograr: los VALUES son inmutables.

Tampoco hay nada malo en declarar public static final valores primitivos, cadenas u otros objetos inmutables public static final int ERROR_CODE = 59; como public static final int ERROR_CODE = 59;

    Intereting Posts