java - online - ¿Por qué la disposición final estática pública es un agujero de seguridad?
head first java (8)
Efectivo java dice:
// Potencial agujero de seguridad!
static public Thing [] VALUES = {...};
¿Puede alguien decirme cuál es el agujero de seguridad?
Tenga en cuenta que una matriz de longitud distinta de cero siempre es mutable, por lo que es incorrecto que una clase tenga un campo de matriz final pública estática o un descriptor de acceso que devuelva dicho campo. Si una clase tiene dicho campo o acceso, los clientes podrán modificar el contenido de la matriz.
- Java efectivo , 2da edición. (página 70)
En esta declaración, un cliente puede modificar Cosa [0], Cosa [1], etc. (es decir, elementos en la matriz).
Para entender por qué esto es un potencial agujero de seguridad y no solo una pobre encapsulación, 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 el código que no es de confianza puede subvertir la restricción que el código de confianza / sandbox está tratando de imponer. En este caso, esto es claramente un problema de seguridad.
Si su código no es parte de una aplicación de seguridad crítica, puede ignorar este problema. Pero IMO esta es una mala idea. En algún momento en el futuro, usted (u otra persona) podría reutilizar su código en un contexto donde la seguridad es una preocupación. En cualquier caso, esta es la razón por la cual el autor considera que los arreglos finales públicos son un problema de seguridad.
Amber dijo esto en un comentario:
No más de un agujero de seguridad que privado, si puede leer el código fuente y / o bytecode de cualquier manera ...
Esto no es verdad.
El hecho de que un "tipo malo" pueda usar código fuente / bytecodes para determinar que existe una entidad private
y se refiere 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 el código no confiable que se ejecuta en un entorno limitado de seguridad (implementado correctamente).
Piensa que solo significa todo lo público vs lo privado. Se supone que es una buena práctica que las variables locales se declaren privadas, y luego usar los métodos get y set, en lugar de acceder directamente a ellas. Los hace un poco más difíciles de meter fuera de su programa. Sobre eso, hasta donde yo sé.
Porque la palabra clave final solo garantiza el valor de referencia (supongamos que es la ubicación de la memoria, por ejemplo), pero no el contenido que contiene.
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 matriz:
private static final String[] VALUES = { "a", "b" };
public static final String[] values()
{
return VALUES.clone();
}
entonces ahora cuando intentamos:
a.values()[0] = "changed value on index 0";
System.out.println(String.format("Result: %s", a.values()[0]));
obtenemos Result: a
y eso es lo que queríamos lograr: los VALUES
son inmutables.
Tampoco hay nada malo en declarar public static final
los valores primitivos, cadenas u otros objetos inmutables como public static final int ERROR_CODE = 59;
Una clase externa puede modificar los contenidos de la matriz, que probablemente no es lo que quiere que hagan los usuarios de su clase (quiere 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 declare esta línea podría pensar que otras clases no pueden modificar los contenidos de la matriz, ya que está marcada como final, pero esto no es cierto, final solo le impide volver a asignar el atributo.
La declaración 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 a pesar de que la referencia de la matriz es constante, los elementos de la matriz todavía se pueden cambiar, y como es un campo, los cambios están desprotegidos, no controlados y normalmente no son bienvenidos.
Para combatir esto, la visibilidad del campo de matriz puede restringirse a privado o privado de paquete, por lo que tiene un cuerpo más pequeño de código para considerar al buscar modificaciones sospechosas. Alternativamente, y a menudo mejor, es eliminar la matriz y usar una ''Lista'', u otro tipo de colección apropiada. Al usar una colección, usted controla si se permiten actualizaciones, ya que todas las actualizaciones pasan por métodos. Puede evitar actualizaciones envolviendo su colección usando Collections.unmodifiableList()
. Pero tenga en cuenta que, aunque la colección es inmutable, también debe asegurarse de que los tipos almacenados en ella también sean inmutables o que reaparezca el riesgo de cambios no solicitados en una supuesta constante.