¿Por qué siempre recomendamos 'HASH (salt + contraseña)'?

21

Navegando a través de este sitio, muchos foros, artículos en línea, siempre hay una forma específica en la que sugerimos almacenar un hash de contraseña:

function (salt, pass) {
   return ( StrongHash(salt + pass) )
}

Pero ¿por qué esta manera exacta ? ¿Por qué no estamos sugiriendo hacer esto?

function (salt, pass) {
   return (StrongHash(( StrongHash(salt) + StrongHash(pass) ))
}

¿O incluso algo como esto?

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data += StrongHash(salt + data)
   }
   return (data)
}

¿O alguna otra combinación loca? ¿Por qué estamos diciendo específicamente hash la concatenación de la sal en bruto y la contraseña en bruto? El hash de ambos hash hash parece ser una alternativa de entropía bastante alta, al igual que el hashing 1000 veces según mi tercer ejemplo. ¿Por qué no pinchamos el primero unas cuantas veces más por el bien de la entropía?

¿Qué tiene de increíble la primera forma?

Por solicitud, ejemplos de esto:

  1. enlace
  2. Hash de contraseña agregar sal + pimienta o es sal suficiente?
  3. Estirando un hash, muchas iteraciones versus una entrada más larga cadena
  4. enlace
  5. enlace
  6. enlace
  7. enlace
  8. enlace
  9. enlace
  10. enlace
pregunta Incognito 15.06.2011 - 16:22
fuente

2 respuestas

41

En realidad, "nosotros" no recomendamos nada de lo que muestres. Las recomendaciones habituales son PBKDF2 , bcrypt o el criptografía de Unix que se utiliza en Linux.

Si la función hash que usas es perfecta oracle aleatorio luego realmente no importa de qué manera ingresas el salt y la contraseña; solo importa el tiempo que se necesita para procesar el salt y la contraseña, y queremos que ese tiempo sea largo, a fin de impedir las búsquedas en el diccionario; De ahí el uso de múltiples iteraciones. Sin embargo , ser un oráculo perfecto al azar es una propiedad difícil para una función hash; no está implícito en las propiedades de seguridad habituales que deben proporcionar las funciones hash seguras (resistencia a las colisiones y preimágenes) y se sabe que algunas funciones hash ampliamente utilizadas no son oráculos aleatorios; p.ej. Las funciones SHA-2 sufren el llamado "ataque de extensión de longitud", que no las hace menos seguras, pero implica cierto cuidado cuando se utiliza la función en esquemas de hashing de contraseña funky. PBKDF2 se usa a menudo con HMAC por ese motivo.

Le recomendamos que no se sienta creativo con los esquemas de cifrado de contraseñas o la criptografía en general. La seguridad se basa en detalles que son sutiles y que no puede probar por sí mismo (durante las pruebas, una función insegura funciona igual de bien que una segura).

    
respondido por el Thomas Pornin 15.06.2011 - 16:52
fuente
9

Sobre los dos propuestos -

function (salt, pass) {    return
    (StrongHash( StrongHash(salt) + StrongHash(pass) ) 
}

No hay bonus aquí. Un hash convierte la información en algo aleatorio. Así que en la primera pasada, hizo dos partes de datos en dos cadenas aleatorias y luego combinó dos cadenas aleatorias. ¿Por qué? La seguridad a través de la oscuridad no ofrece ningún beneficio. Los elementos críticos de la solución generalmente propuesta son:

  • combinar sal y amp; contraseña para que el salt pueda proporcionar un factor de caos adicional para crear el hash de una contraseña
  • de una manera hash el conglomerado para hacer una cadena aparentemente aleatoria.

No puede ser más aleatorio que aleatorio, y con seguridad es bueno evitar el trabajo que no tiene un propósito.

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data += StrongHash(salt + data)
   }
   return (data)
}

Lo primero que sucede aquí es que a los datos se les proporciona el salt y la contraseña. Por lo que su salida se verá como:

<Salt><Password><randomString0><randomString1>....<randomString999>

<Salt> = the salt in cleartext
<Password> = the password in cleartext
<randomString> = a series of different random strings.

El código tal como está escrito acaba de exponer la contraseña, por lo que todas las cadenas aleatorias no tienen ningún propósito.

Una solución a este problema sería:

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data = StrongHash(salt + data)
   }
   return (data)
}

Observe la eliminación de + = y cambie a una tarea simple. Es un pequeño cambio, pero significa que ahora sus datos finales son una sola cadena aleatoria de la longitud que genera su algoritmo hash.

Probablemente esté bien desde el punto de vista de la seguridad, pero, una vez más, no hay una mejora real con respecto a la versión original simple. La repetición de muchos hash recursivos no agrega seguridad: su primera pasada con un algoritmo de hash debería producir un resultado aleatorio. Hashear lo mismo una y otra vez no hace nada en el mejor de los casos, y el peor de los casos podría terminar reduciendo el valor del algoritmo hash.

La primera forma ofrece un beneficio muy importante: el director de KISS. Mantenlo simple. Cuando repetir la función no ofrece beneficios, no hay razón para hacer que su lógica sea más complicada, más larga de procesar, más abierta al error y más difícil de depurar.

También: con la criptografía, todos los algoritmos deben venir con un manual de usuario que llene su cubículo promedio. La discusión sobre las teclas débiles, los problemas con la repetición, la exposición y otros debates de entrada / salida matemática mantendrá a los matemáticos llenos de temas de tesis por el resto de la eternidad. Hasta que no haya un algoritmo específico en juego, es difícil discutir las repercusiones reales, pero en general es una buena política dejar las repeticiones y permutaciones hasta el diseño del algoritmo en lugar de intentar ayudar. Muchos algoritmos hash ya tienen ciclos de repetición y recursión, lo que significa que el usuario no tiene motivos para hacer más.

    
respondido por el bethlakshmi 15.06.2011 - 18:48
fuente

Lea otras preguntas en las etiquetas