¿La serialización y los HashMaps son seguros?

2

He leído algo en esta área y hay muy poca información sobre la seguridad de un HashMap. El único artículo que pude encontrar fue en el sitio IBM's Developer Works .

Qué función de hash se utiliza para HashMap en Java. Esa es realmente la pregunta más importante con respecto a la seguridad de HashMaps, ¿verdad?

    
pregunta Ramonster 24.03.2015 - 15:29
fuente

4 respuestas

3

Hay dos tipos diferentes de funciones hash:

Las funciones criptográficas de hash hacen promesas de seguridad específicas, como ser difíciles de invertir, crear colisiones y otras.

Las funciones de hash no criptográficas regulares, como la utilizada en java.util.HashMap , están diseñadas para ser lo más rápidas posible, para distribuir las entradas de la manera más uniforme posible en toda la gama de depósitos de hash , y no suelen hacer promesas de seguridad específicas.

No obstante, eso no quiere decir que no haya problemas de seguridad con las funciones hash regulares. Por ejemplo, ataques de complejidad algorítmica , donde el atacante elige claves únicas que saben que se asignan al mismo hash valor, lo que les permite montar un ataque de denegación de servicio.

    
respondido por el Stuart Caie 24.03.2015 - 16:21
fuente
1

Utiliza la función hashCode (). Una explicación sencilla y breve de cómo funciona esta función se puede leer aquí y una pseudo implementación es aquí .

    
respondido por el user45139 24.03.2015 - 15:43
fuente
1

Como siempre en seguridad, ¿contra qué amenaza intenta protegerse?

Parece que de la pregunta le preocupa la disponibilidad. Normalmente, una tabla hash tendrá un rendimiento limitado de O (1) para operaciones simples, pero se degradará al peor de los casos de O (n). (Consulte Pautas de codificación segura para Java SE ). Diga, ¿un servidor web? use recursos desproporcionados al tamaño de una solicitud en el peor de los casos maliciosamente diseñada. El artículo vinculado en la questio trata sobre la serialización de Java, que es un agujero diferente (y realmente no protege la disponibilidad).

Todo depende de la implementación.

Hace aproximadamente una década, la implementación de Sun de HashMap generalmente solo usaba un módulo de lo que fuera de Object.hashCode . Ver por ejemplo, la definición de String.hashCode . Para String es trivial generar un texto diferente con el mismo hash. Dale a un antiguo HashMap un montón de claves con el mismo hash, solo usarán un cubo, y el rendimiento será terrible.

Más tarde, la implementación de Sun mezcló el valor hash antes de tomar el módulo. Sin embargo, si el hash era el mismo para empezar, seguirá siendo el mismo.

TreeMap resuelve los problemas, pero el rendimiento benigno del caso no es el mejor, aunque ha mejorado.

Más recientemente, para aplacar a aquellos que no saben cómo funcionan las tablas hash, OpenJDK utilizó variantes de MurmurHash, con una semilla aleatoria por instancia, para String cuando hay muchas colisiones. Esto reemplaza a String.hashCode - simplemente agregando el mismo número a un hash fijo no alterará las colisiones. Aunque técnicamente "no criptográfico", es supuestamente difícil generar colisiones sin conocer la semilla secreta. Siempre hay canales laterales.

Ahora reemplazando MurmurHash, es el algoritmo obvio de usar un árbol en lugar de una lista lineal para grupos cuando ha habido muchas colisiones. Como HashMap nunca fue diseñado para esto, es un hack escandaloso, pero es un hack en el que aparece la biblioteca con olor a rosas, incluso cuando se abusa (en su mayoría). El algoritmo alternativo solo entra en uso cuando hay muchas colisiones (como con Murmur) y solo en los casos en que cada clave parece implementar Comparable compatible con el tipo.

    
respondido por el Tom Hawtin - tackline 25.03.2015 - 13:37
fuente
0

Los HashMaps no se utilizan realmente con fines de seguridad. Solo se utilizan para mapear claves únicas a objetos. Esto depende del objeto que estés usando en tu HashMap. Cada objeto debe definir su propia función public int hashCode() . Esta función se aplica a cada objeto cuando put ting en un HashMap. Depende del desarrollador asegurarse de que su hashCode() haga un trabajo suficiente para el propósito del objeto. Pero como verás, HashMap agrega un hash interno adicional para ayudar con esto.

Si observa el código fuente para HashMap::put Veré en la línea 389 que llama al hashCode para el objeto como un parámetro a una función estática llamada hash() .

  374       /**
  375        * Associates the specified value with the specified key in this map.
  376        * If the map previously contained a mapping for the key, the old
  377        * value is replaced.
  378        *
  379        * @param key key with which the specified value is to be associated
  380        * @param value value to be associated with the specified key
  381        * @return the previous value associated with <tt>key</tt>, or
  382        *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
  383        *         (A <tt>null</tt> return can also indicate that the map
  384        *         previously associated <tt>null</tt> with <tt>key</tt>.)
  385        */
  386       public V put(K key, V value) {
  387           if (key == null)
  388               return putForNullKey(value);
  389           int hash = hash(key.hashCode());
  390           int i = indexFor(hash, table.length);
  391           for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  392               Object k;
  393               if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  394                   V oldValue = e.value;
  395                   e.value = value;
  396                   e.recordAccess(this);
  397                   return oldValue;
  398               }
  399           }
  400   
  401           modCount++;
  402           addEntry(hash, key, value, i);
  403           return null;
  404       }

Así es como se ve la función static int hash(int h) .

  257       /**
  258        * Applies a supplemental hash function to a given hashCode, which
  259        * defends against poor quality hash functions.  This is critical
  260        * because HashMap uses power-of-two length hash tables, that
  261        * otherwise encounter collisions for hashCodes that do not differ
  262        * in lower bits. Note: Null keys always map to hash 0, thus index 0.
  263        */
  264       static int hash(int h) {
  265           // This function ensures that hashCodes that differ only by
  266           // constant multiples at each bit position have a bounded
  267           // number of collisions (approximately 8 at default load factor).
  268           h ^= (h >>> 20) ^ (h >>> 12);
  269           return h ^ (h >>> 7) ^ (h >>> 4);
  270       }

Los comentarios explican los motivos para aplicar la función de hashing suplementario.

    
respondido por el RoraΖ 24.03.2015 - 15:57
fuente

Lea otras preguntas en las etiquetas