¿Qué tan seguro es el código hash de Java ()?

20

En nuestras vistas en una aplicación web de Java, actualmente estoy usando hashCode como Id. para objetos, de modo que al final del servidor pueda recuperar el mismo objeto.

Sin embargo, me pregunto qué tan seguro es el hashCode de Java para que alguien no pueda hackearlo para recuperar los objetos de otra persona. No estoy muy inclinado hacia el mecanismo de cifrado-descifrado ya que causa mucha CPU.

¿Qué otros mecanismos rápidos pero seguros puedo usar?

    
pregunta Novice User 07.03.2014 - 08:33
fuente

4 respuestas

53

Estás rompiendo uno de los tabos hashCode() ; estás utilizando su salida como un identificador de clave. Eso está mal.

Verá, la salida de hashCode() (en su implementación predeterminada) es un entero sin signo de 32 bits, aproximadamente 4 mil millones de códigos hash únicos. ¿Suena bastante? Bueno, no tanto. La aplicación del problema de cumpleaños en este caso muestra que con aproximadamente 77000 objetos, tiene aproximadamente un 50% de posibilidades de colisión. 50% de probabilidad de que dos objetos tengan el mismo código hash.

Otro problema es que la implementación de hashCode() puede cambiar de una versión de Java a la otra. No pretende ser un identificador permanente de un objeto, por lo que no hay nada que lo obligue a ser coherente en todas las versiones.

Si insiste en usar hashes como identificadores de objetos, entonces es mucho mejor tener su propio método en lugar de hashCode() para usar con sus identificadores clave (por ejemplo, getMySpecialHashKey() . Puede usar algo como MessageDigest.getInstance("SHA-256") para digiere el objeto en una buena clave de 256 bits.

Mi recomendación: Deshazte de la idea completa de hashear el objeto y más bien genera un identificador aleatorio para tu objeto cuando lo construyas. Algo a lo largo de las líneas de (en Java)

SecureRandom secRand = new SecureRandom();
byte[] objIdBytes = new byte[16]; //128-bit
secRand.nextBytes(objIdBytes);
String objId = Base64.encodeBase64String(objIdBytes); //Here's your ID

También parece vincular el acceso a un objeto solo al conocimiento de su clave. Eso también es incorrecto. Se necesita un modelo adecuado basado en permisos con la autenticación y autorización adecuadas.

    
respondido por el Adi 07.03.2014 - 09:40
fuente
30

Java hashCode() nunca fue diseñado para usarse de esta manera. ¡No lo hagas nunca! Incluso es legal (aunque no se recomienda) que todas las instancias de una clase devuelvan el mismo código hash. El contrato en Java es "dos objetos que se consideran iguales deben tener el mismo código hash". Ni mas ni menos. Por ejemplo, sería válido devolver el código hash 1 para todos los números desiguales y 0 para los pares.

hashCode se usa para búsquedas más rápidas en colecciones como HashMap y las colisiones se esperan .

Muchas clases definen su propia versión de hashCode() , y si conoce el código, a menudo puede decir o adivinar fácilmente el código hash.

Por lo tanto, esto es absolutamente inseguro.

    
respondido por el Axel 07.03.2014 - 12:12
fuente
12

No es criptográficamente seguro, porque eso no es parte de sus requisitos.

La forma en que se implementa el hashCode es un detalle de implementación hasta la JVM y puede ser diferente para diferentes tipos de objetos (los objetos pueden anular el método hashCode y proporcionar una implementación propia).

El propósito del código hash de Java es identificar los objetos al colocarlos en tablas hash. Su principal requisito es el rendimiento. También tiene una longitud de solo 32 bits, que es demasiado corta para evitar colisiones. Para su propósito previsto (tablas hash), dos objetos que tienen el mismo hash son solo un problema menor, pero identificar objetos sin ambigüedades es un gran problema.

Pero, por lo general, no debe permitir que ningún usuario acceda a ningún objeto solo porque conoce el código hash de los objetos. Utilice un esquema adecuado de gestión de derechos. Utilice cuentas de usuario protegidas por contraseña donde cada usuario tenga un conjunto diferente de parámetros de permiso. Cuando el usuario intenta acceder a un objeto, verifique si sus permisos le permiten hacerlo y rechazar la solicitud cuando no lo hacen.

    
respondido por el Philipp 07.03.2014 - 09:31
fuente
2

Ciertamente, no es lo suficientemente seguro para una situación donde los valores de adivinación pueden revelar información.

Al menos algunas de las anulaciones ni siquiera son lo suficientemente seguras como para utilizarlas como un código hash en vista de una entrada arbitraria seleccionada por el usuario (es realmente fácil realizar un ataque hash-DoS contra cualquier cosa utilizando la anulación de String.hashCode() de Java ).

En los casos en los que desee un identificador, recomiendo tomar un identificador simple (por ejemplo, una clave numérica en una base de datos, un entero incrementado de forma atómica que es una clave en una tabla hash, etc.) y luego agregar un hash criptográfico de eso y una sal.

Es decir, su ID expuesta públicamente sería de la forma (en lenguaje agnóstico):

Concatenate(PrivateID, HexString(SHA256(UTF8Bytes(Concatenate(Salt, PrivateID)))))

(Podrías eliminar parte del hash para obtener una ID más pequeña a costa del tiempo reducido para fuerza bruta).

Luego, la ID privada se puede obtener como una subcadena, y la ID completa se puede verificar nuevamente. El procedimiento general también es fácil de portar entre idiomas.

El puñado de ciclos de CPU que costará no va a tener un gran impacto en relación con el resto del sistema, a menos que su sistema sea tan trivial que no vaya a utilizar mucha CPU de todos modos, a menos que esté ejecutar esto en algo realmente de baja potencia (como en, mucho menos potente que un teléfono barato) no será una preocupación.

En los casos en los que realmente desea utilizar un código hash como un código hash y tiene que lidiar con la entrada seleccionada por el usuario, use un algoritmo hash que se pueda sembrar (por ejemplo, SpookyHash) y base su semilla en el tiempo de inicio ( o mejor aún, una combinación de tiempo de inicio y el momento en que se crea el contenedor de hash). (Nada que ver con los hash criptográficos, por lo que pueden ser mucho más rápidos; el único riesgo de seguridad que esto evita es el hash-DoSing).

    
respondido por el Jon Hanna 07.03.2014 - 18:07
fuente

Lea otras preguntas en las etiquetas