Password Hashing: ¿agregar sal + pimienta o es suficiente sal?

213

Tenga en cuenta: soy consciente de que el método correcto para el hashing de almacenamiento seguro de contraseñas es scrypt o bcrypt. Esta pregunta no es para implementación en software real, es para mi propia comprensión.

Relacionados

Fondo
Por lo que sé, el método recomendado / aprobado para almacenar los verificadores de contraseñas es almacenar:

$verifier = $salt + hash( $salt + $password )

Donde:

  • hash() es un algoritmo de hash criptográfico
  • $salt es un alto valor de entropía aleatorio, distribuido uniformemente
  • $password es la contraseña introducida por el usuario

Algunas personas recomiendan agregar una clave secreta a la mezcla (a veces llamada pepper ). Donde la pimienta es una constante secreta, de alta entropía y específica del sistema.

La razón parece ser que incluso si el atacante obtiene los verificadores de la contraseña, es muy probable que no sepa el valor de la pimienta. Así que montar un ataque exitoso se vuelve más difícil.

Por lo tanto, mi pregunta es:
¿La adición de un valor de pimienta además de una sal cuando las contraseñas de hash aumenta la seguridad general?

¿O el aumento de seguridad percibido se basa en suposiciones falsas?

Actualización rápida
Sé el propósito de $salt (escribí bastante respuesta larga en StackOverflow al respecto) la clave $pepper adicional no está mejorando en lo que hace la sal.
La pregunta es, ¿el $pepper agrega algún otro de seguridad a lo que hace la sal?

    
pregunta Jacco 22.04.2011 - 11:53
fuente

7 respuestas

178

En algunas circunstancias, los pimientos pueden ser útiles.

Como ejemplo típico, digamos que estás creando una aplicación web. Consiste en un código de aplicación web (que se ejecuta en algún marco de aplicación web, ASP.NET MVC, Pyramid on Python, no importa ) y una base de datos SQL para almacenamiento. La aplicación web y la base de datos SQL se ejecutan en diferentes servidores físicos .

El ataque más común contra la base de datos es un ataque de inyección SQL exitoso. Este tipo de ataque no necesariamente obtiene acceso a su código de aplicación web, porque la aplicación web se ejecuta en un servidor diferente & ID de usuario.

Debe almacenar las contraseñas de forma segura en la base de datos, y encontrar algo en la forma de:

$hashed_password = hash( $salt . $password )

donde $salt se almacena en texto plano en la base de datos, junto con la representación $hashed_password y elegidos al azar para cada contraseña nueva o cambiada .

El aspecto más importante de cada esquema de hash de contraseñas es que hash es una función hash criptográficamente segura lenta , consulte enlace para obtener más información sobre los antecedentes.

La pregunta es, entonces, dado que es un esfuerzo casi nulo para agregar un valor constante al código de la aplicación, y que el código de la aplicación normalmente no se verá comprometido durante un ataque de inyección de SQL, ¿es lo siguiente sustancialmente mejor que lo anterior?

$hashed_password = hash( $pepper . $salt . $password )

donde $salt se almacena en texto sin formato en la base de datos, y $pepper es una constante almacenada en texto sin formato en el código de la aplicación (o configuración si el código se usa en múltiples servidores o la fuente es pública).

Es fácil agregar este $pepper : solo estás creando una constante en tu código, ingresando un gran valor aleatorio criptográficamente seguro (por ejemplo, 32 bytes de / dev / urandom hex o base64 codificado) y usándolo constante en la función de hashing de contraseñas. Si tiene usuarios existentes, necesita una estrategia de migración, por ejemplo, vuelva a introducir la contraseña en el siguiente inicio de sesión y almacene un número de versión de la estrategia de hash de contraseña junto con el hash.

Respuesta:

El uso de $pepper se agrega a la fuerza del hash de contraseña si el compromiso de la base de datos no implica el compromiso de la aplicación . Sin conocimiento de la pimienta las contraseñas permanecen completamente seguras. Debido a la sal específica de la contraseña, ni siquiera puede descubrir si dos contraseñas en la base de datos son iguales o no.

La razón es que hash($pepper . $salt . $password) construye efectivamente una función pseudoaleatoria con $pepper como clave y $salt.$password como entrada (para candidatos sane hash como PBKDF2 con SHA *, bcrypt o scrypt). Dos de las garantías de una función pseudoaleatoria son que no puede deducir la entrada de la salida bajo una clave secreta y tampoco la salida de la entrada sin el conocimiento de la clave. Esto se parece mucho a la propiedad unidireccional de las funciones hash, pero la diferencia radica en el hecho de que con valores de entropía bajos, como contraseñas, puede enumerar efectivamente todos los valores posibles y calcular las imágenes bajo la función hash pública y así encontrar el valor cuyo valor La imagen coincide con la imagen previa. Con una función pseudoaleatoria, no puede hacerlo sin la clave (es decir, sin la pimienta), ya que ni siquiera puede calcular la imagen de un solo valor sin la clave.

El importante papel del $salt en esta configuración entra en juego si tiene acceso a la base de datos durante un tiempo prolongado y normalmente puede trabajar con la aplicación desde el exterior. Sin el $salt , podría establecer la contraseña de una cuenta que controle con un valor conocido $passwordKnown y comparar el hash con la contraseña de una contraseña desconocida $passwordSecret . Como hash($pepper . $passwordKnown)==hash($pepper . $passwordSecret) si y solo si $passwordKnown==$passwordSecret puede comparar una contraseña desconocida con cualquier valor elegido (como tecnicidad supongo que la resistencia a la colisión de la función hash). Pero con la sal obtienes hash($pepper . $salt1 . $passwordKnown)==hash($pepper . $salt2 . $passwordSecret) si y solo si $salt1 . $passwordKnown == $salt2 . $passwordSecret y como $salt1 y $salt2 fueron elegidos al azar para $passwordKnown y respectivamente $passwordSecret las sales nunca serán las mismas (asumiendo valores aleatorios suficientemente grandes como 256 bits) y, por lo tanto, ya no se pueden comparar las contraseñas entre sí.

    
respondido por el Jesper Mortensen 10.07.2018 - 00:48
fuente
88

(Nota: usar una sal es solo la mitad del trabajo; también debe hacer que la función hash sea lenta, por lo que el ataque de una sola contraseña de baja entropía es aún difícil. La lentitud generalmente se logra a través de múltiples iteraciones o hashing la concatenación de 10000 copias de la sal y la contraseña.)

Lo que tu "pimienta" hace es que transforma el hash en un MAC . Hacer un MAC bueno y seguro a partir de una función hash no es fácil, así que es mejor que uses HMAC en lugar de un método casero. construir (la forma teórica de decirlo es que una función hash resistente a la colisión no es necesariamente indistinguible de un oráculo aleatorio).

Con un MAC, puede obtener algo de seguridad en el siguiente sentido: posiblemente, el acceso de lectura de la base de datos por parte del atacante podría dejar de ser un problema real. La tecla MAC (el "pimiento") puede concentrar la necesidad de confidencialidad. Sin embargo, esto se basa en que MAC también es una función de una sola vía, que es una propiedad que obtendrás de muchas construcciones de MAC (incluyendo HMAC) pero que no está realmente garantizada criptográficamente hablando (hay sutilezas).

El "pimiento" implica que tiene una clave para administrar, incluido el almacenamiento seguro de una manera que resiste los reinicios. Una clave es pequeña y cabe en la RAM, pero, debido a los requisitos de almacenamiento, no está claro si realmente mejora la seguridad. Un atacante que puede leer la base de datos completa generalmente también puede leer el disco duro completo, incluido cualquier archivo "protegido". El tamaño pequeño de la clave puede permitir algunas configuraciones avanzadas, por ejemplo, la clave se almacena en tarjetas inteligentes que se utilizan en el momento del arranque pero no se dejan conectadas después. Para resumir, si vale la pena el esfuerzo depende del contexto, en general, lo recomendaría para evitar la complejidad agregada.

    
respondido por el Thomas Pornin 22.04.2011 - 16:53
fuente
25

Me gustaría señalar qué puede hacer realmente un pimiento.

¿Cuándo ayuda un pimiento?

Como los otros ya han señalado, agregar un pimiento es solo una ventaja, siempre que el atacante tenga acceso a los valores hash en la base de datos, pero no tenga control sobre el servidor y, por lo tanto, no lo sepa la pimienta . Esto es típico de la inyección SQL, probablemente uno de los ataques más utilizados, porque es muy fácil de hacer.

¿Qué mejora un pimiento?

$hashValue = bcrypt('12345', $cost, $salt);

Esta contraseña puede obtenerse fácilmente con un ataque de diccionario, incluso si usó correctamente una función de derivación de clave lenta. Coloque las contraseñas más utilizadas en un diccionario y fuerza bruta con estas contraseñas débiles. Es muy probable que encontremos la contraseña en (también) muchos casos.

$hashValue = bcrypt('12345anm8e3M-83*2cQ1mlZaU', $cost, $salt);

Con la pimienta, la contraseña débil crece en longitud, ahora contiene caracteres especiales y, lo que es más importante, no la encontrará en ningún diccionario. Por lo tanto, siempre que la pimienta se mantenga en secreto, evita los ataques de diccionario , en este caso puede proteger contraseñas débiles.

Editar:

Hay una mejor manera de agregar una clave del lado del servidor, que usarla como un pimiento. Con un pimiento, un atacante debe obtener privilegios adicionales en el servidor para obtener la clave. La misma ventaja que obtenemos al calcular el hash primero y luego al cifrar el hash con la clave del lado del servidor (cifrado de dos vías). Esto nos da la opción de intercambiar la clave siempre que sea necesario.

$hash = bcrypt($passwort, $salt);
$encryptedHash = encrypt($hash, $serverSideKey);
    
respondido por el martinstoeckli 02.11.2012 - 16:52
fuente
9

El artículo sobre la invención de la salazón y las iteraciones, para contraseñas de Unix ( Contraseña de seguridad: un historial de casos, Morris y Thompson, 1978 ), también describieron el equivalente a un pimiento:

  

Los primeros ocho caracteres de la contraseña del usuario se utilizan   como clave para el DES; entonces el algoritmo se utiliza para cifrar una constante. Aunque esta constante es cero en el   En este momento, es de fácil acceso y puede depender de la instalación.

Sin embargo, no he oído que se use. ¿Alguien más?

    
respondido por el nealmcb 10.05.2011 - 07:21
fuente
7

Solo por BTW, las nuevas Pautas de Idendidad Digital (Borrador) del NIST también recomiendan utilizar Pepper:

enlace

5.1.1.2 Verificador de secretos memorizados:

  

... Una función de hash con clave (por ejemplo, HMAC [FIPS198-1]), con la clave almacenada por separado de los autenticadores de hash (por ejemplo, en un módulo de seguridad de hardware) DEBE usarse para resistir aún más los ataques de diccionario contra los almacenados Autenticadores hash.

    
respondido por el eckes 06.05.2017 - 20:08
fuente
4

Considere este escenario:

Estoy a punto de entrar en un sitio web X utilizando una inyección de SQL para recuperar una lista de usuarios, con sus hashes de contraseña y sal. Supongamos que el sitio web X también está utilizando un chile global.

Todo lo que tendría que hacer sería registrar a un usuario en el sitio web X con un nombre de usuario y contraseña conocidos antes de la inyección de SQL. Entonces sabría, para un registro particular en la base de datos, el hash de contraseña, la contraseña de texto sin formato, la sal (almacenada como texto sin formato) y sería computacionalmente trivial descifrar el pimiento global sobre la base de este registro. .

En realidad, un pimiento sería una forma de ralentizar a un atacante durante una cantidad trivial de tiempo de sobrecarga. No tendrían que hacer fuerza bruta con la contraseña + sal + pimienta, según lo previsto, solo la pimienta.

Lo anterior es una forma de ataque de texto simple elegido . Mientras los atacantes conozcan el algoritmo (hash ()), la salida ($ hashed_password) y todas las entradas menos las "constantes" $ salt & $ password y "variable" $ pepper), pueden "resolver" x "como una ecuación de álgebra lineal (h = s + p + x == hsp = x), pero por fuerza bruta, por supuesto. Hacer que la pimienta tenga más de 56 bytes (448 bits), el límite de bcrypt, aumenta el costo del tiempo y es tan bueno como bcrypt, pero aún así puede no ser tan bueno como scrypt. Por lo tanto, siempre que el pimiento sea suficientemente largo, es una mejora.

    
respondido por el Alex R 31.08.2013 - 08:20
fuente
1

No estoy muy familiarizado con cómo un servidor podría ocultar una constante global de pimienta, pero mi opinión es que tarde o temprano un hacker que haya penetrado en el servidor descubrirá cómo capturar el valor de la pimienta. Hacer un valor de pimienta totalmente seguro requeriría un hardware especial. Una forma de hacerlo sería utilizar una placa FPGA instalada en el servidor. El FPGA contendría el código utilizado para realizar el hash, incluido el valor de pimienta y todos los cálculos de hash se producen dentro del FPGA. Con el FPGA, la programación puede ser una función unidireccional. El chile puede programarse pero no hay instrucciones que se puedan enviar para leerlo nuevamente. La pimienta se almacenaría en un pedazo de papel encerrado en una caja fuerte. Si la pimienta es de más de 128 bits generados al azar, no habría una forma práctica de determinarlo.
No estoy seguro de lo práctico que sería esto, ya que aumentaría el costo del hardware del servidor.

    
respondido por el Brian Sparks 07.09.2014 - 20:04
fuente

Lea otras preguntas en las etiquetas