¿Existe algún riesgo de seguridad al almacenar variaciones de contraseñas con hash?

16

Por ejemplo, si hipotéticamente un requisito de la aplicación era informar a los usuarios cuándo su contraseña podría haber fallado debido a que estaba activado el bloqueo de mayúsculas, e hipotéticamente no había forma de que la aplicación realmente supiera que el bloqueo de mayúsculas estaba activado, es ¿Existe algún riesgo de seguridad inherente al almacenar una contraseña con hash, así como una versión con "bloqueo de mayúsculas" de una contraseña para que una contraseña fallida también pueda compararse con la versión del "bloqueo de mayúsculas"?

Si se infringió una base de datos que contiene cuentas de usuario con esta configuración, ¿la existencia del hash de contraseña "mayúsculas" además del hash de contraseña normal hará que las contraseñas sean más vulnerables de lo que serían?

Tenga en cuenta que esto es hipotético y me interesan más las implicaciones de seguridad que si se trata de una buena práctica de programación.

    
pregunta Joe M. 09.05.2012 - 22:39
fuente

6 respuestas

6

Otro enfoque, si desea permitir diferentes variaciones de contraseña.

Cuando un usuario inicia sesión en su aplicación, normalmente obtendría una versión de texto simple de la contraseña (con suerte sobre SSL) y luego la modificará y la comparará con su valor hash almacenado.

Por lo tanto, no hay necesidad real de almacenar diferentes versiones de hash. Puede almacenar un hash de contraseña , pero cuando el usuario intenta iniciar sesión, realiza esa transformación en la contraseña proporcionada por el usuario en el momento del inicio de sesión y luego codifica esas variaciones diferentes. p.ej. Si la contraseña proporcionada no pudo compararse con el hash, aplique la transformación caps-lock , haga clic en hash y luego vuelva a verificar el hash almacenado. Si coincide, puede decidir darle al usuario acceso a su aplicación.

De esta manera, solo almacena una versión (canónica) del hash, pero permite varias permutaciones de la misma contraseña.

En términos de escenarios de ataque:

  • Ataque sin conexión contra tus hashes de contraseña: sigue siendo el mismo
  • Ataque en línea que intenta autenticarse con diferentes contraseñas: esto será más fácil en relación con el número de posibles permutaciones

Sin embargo, por lo general, debería ser más fácil limitar el número de intentos posibles de forzar la fuerza bruta o la contraseña para hacerlo lo suficientemente difícil. Puede leer más sobre algunas técnicas aquí que probablemente debería implementar de todos modos.

Todavía seré muy cuidadoso con las posibles permutaciones y mediré cuánto podrían reducir la entropía de la contraseña, por supuesto, pero al menos no es necesario almacenar varias versiones con hash para hacer esto.

    
respondido por el Yoav Aner 10.05.2012 - 07:58
fuente
8

Pregunta interesante. Supongo que depende de cuáles y cuántas versiones esté almacenando. La principal preocupación al hacerlo es cuánto está reduciendo el espacio de búsqueda / entropía.

Si, por ejemplo, la versión mayúscula de la contraseña es una versión en mayúscula de la contraseña, al almacenarla de esta manera, está reduciendo La entropía de la contraseña. El atacante en este caso solo tiene que buscar usando la versión caps-lock usando solo el juego de caracteres en mayúscula. Eso les da un trabajo mucho más fácil.

Sin embargo, si la versión caps-lock es simplemente un caso de las letras, es decir, la contraseña normal == aXbJklMP y la versión caps-lock == AxBjKLmp , entonces ' Probablemente no estamos reduciendo enormemente el espacio de búsqueda. Todavía hay dos contraseñas posibles en lugar de una, lo que hace que la búsqueda tenga el doble de posibilidades de encontrar una de esas contraseñas ...

    
respondido por el Yoav Aner 09.05.2012 - 23:01
fuente
4

Ampliando mi comentario anterior:

  

Si los dos hashes almacenados (con y sin la transformación de bloqueo de mayúsculas) son iguales, podemos saber que el usuario no tiene letras en su contraseña. (O al menos no tiene letras minúsculas en su contraseña, según cómo realice la transformación).

Dado que Mac y Windows (y Linux) manejan mayúsculas de manera diferente, tendrá que almacenar dos variaciones del hash de transformación de bloqueo de mayúsculas: la inversión de mayúsculas y minúsculas (Windows / Linux) y las mayúsculas (Mac). Ahora podemos determinar aún más acerca de la contraseña de los hashes.

  1. Si los tres hashes son iguales, el usuario no tiene letras (mayúsculas o minúsculas) en su contraseña.
  2. Si el hash de transformación de Windows es diferente pero el hash de transformación de Mac es el mismo que el hash principal, entonces el usuario tiene mayúsculas en su contraseña pero no mayúsculas.
  3. Si los tres hashes son diferentes, el usuario tiene mayúsculas y minúsculas en su contraseña.

Otro pensamiento: ¿es seguro aplicar la misma sal a las tres variaciones? Aunque creo que debería serlo, no veo ninguna ventaja significativa al hacerlo. Si aplica sal diferente a los tres hashes, pienso las filtraciones de información anteriores se niegan. Tenga en cuenta que no soy criptógrafo, aunque no debería haber ninguna fuga de información al incluir tres contraseñas relacionadas y posiblemente idénticas con tres sales diferentes, es posible que se requiera una sal más larga para que esté seguro.

Otros problemas:

Ya que tenemos tres variaciones de hash de contraseña que deben verificarse cada vez que un usuario inicia sesión, se deberán calcular los tres hashes. Si está utilizando bcrypt (o similar) con un número apropiado de rondas de hashing, querrá reducir esa cantidad de rondas para que el tiempo tomado sea aproximadamente 1/3 del valor anterior. (Suponiendo que establezca el número de rondas en el máximo que puede manejar y ahora necesita calcular tres veces el número de hashes por inicio de sesión).

La razón por la que necesita calcular los tres hashes incluso si la primera o la segunda coincidencia es que si no lo hace, habilita la enumeración de credenciales a través de los ataques de tiempo. En teoría, para evitar la enumeración de credenciales, debe proporcionar exactamente la misma respuesta si el usuario no existe o si existe, pero la contraseña es incorrecta. Si devuelve una respuesta idéntica para ambos casos, pero toma milisegundos cuando el usuario no existe y todo un segundo cuando el usuario existe, todavía tiene habilitada la enumeración de credenciales.

Todo hasta ahora, creo que debería ser relativamente seguro si usa diferentes sales para los tres hashes, siempre calcule las tres variaciones de la contraseña suministrada y reduzca el número de rondas para que el tiempo se reduzca en 1/3.

Sin embargo, podría ser más sencillo almacenar solo un hash, verifique que no haya ninguna y el hash no coincida con la contraseña provista por el usuario, sugiérales que pueden tener mayúsculas.

Pensamientos tardíos

No hay necesidad de almacenar tres hashes diferentes como sugerí anteriormente si planea aceptar la transformación de estilo Mac. Solo escribe en mayúsculas todas las contraseñas antes de que estén encriptadas y solo almacena la versión en mayúsculas. Esto también evita los ataques de tiempo ya que solo necesita calcular un hash por inicio de sesión.

Al hacer esto, ha reducido el número de letras / números / símbolos posibles que las personas pueden usar en 26, por lo que puede sugerir que los usuarios utilicen una contraseña ligeramente más larga para compensar.

    
respondido por el Ladadadada 10.05.2012 - 11:39
fuente
3

Sucede que almacenar ambos hashes, o invertir el efecto de bloqueo de mayúsculas y probar ambas versiones, realmente reduce la seguridad en un factor que es entre 1 y 2 . Es un poco difícil de ver, así que definamos las cosas claramente.

Estoy utilizando la noción de mayúsculas de reverslock. Si el efecto de capslock es realmente un efecto de mayúsculas, nunca debes aceptar o almacenar esa versión en mayúsculas; en su lugar, devuelve una advertencia como @ D.W. sugiere.

Supongo que utilizas una función hash lenta y salada como bcrypt (si no lo hagas, eso es un problema mayor y deberías solucionarlo primero). La parte "lenta" se puede configurar con un recuento de iteraciones que aumenta tanto como puede, según dos restricciones: el presupuesto de CPU para el hashing (dependiendo de cuánto CPU libre que tienes y cuántas conexiones de clientes por segundo), y la paciencia del usuario (que nunca es muy alta). El costo para el atacante es directamente proporcional al conteo de iteraciones. Si almacena dos valores hash (para la versión "normal" y "bloqueada" de la contraseña), ambos deben tener su propia sal.

Cuando "intentas" la contraseña enviada por el usuario y luego "intentas de nuevo" con una versión de la misma contraseña con bloqueo de mayúsculas, en realidad hash de hashing dos veces, por lo que hay una sobrecarga en tus restricciones. En promedio, el esfuerzo de la CPU se multiplicará por 1 + f , donde f es la proporción de contraseñas incorrectas ( f = 0 si todas las los usuarios escriben perfectamente, f está muy cerca de 1 si todos los usuarios son chimpancés que deben probar una docena de veces antes de escribir su contraseña correctamente). Además, cada vez que tenga que probar la versión de la contraseña con bloqueo de mayúsculas, el usuario deberá esperar dos veces más antes de que se le conceda el acceso (si la versión de bloqueo de mayúsculas resulta ser correcta) o ser rechazado de forma ignominiosa (si la contraseña es realmente incorrecta cerrojo o no). Hasta cierto punto, los usuarios promedio son un poco más comprensivos acerca de los retrasos cuando sienten que es su culpa, porque escribieron mal, pero yo no contaría con eso.

El efecto neto es que probar dos versiones de la contraseña aumenta el costo en un factor que está entre 1 y 2; correspondientemente, entonces debes disminuir la cuenta de iteraciones por ese factor, y la efectividad del atacante se multiplica por ese factor.

Esto es realmente un compromiso entre la experiencia del usuario (que en muchos casos significa "costos del servicio de asistencia") y la seguridad. Si es posible, probablemente sea mejor detectar el bloqueo de mayúsculas y avisar al usuario antes de ingresar la contraseña; sin embargo, esto puede resultar difícil (conozco un sitio que logra hacerlo cuando el cliente es Internet Explorer, pero falla con Chrome y Firefox; en cambio, emite advertencias visibles para cada letra mayúscula, lo cual es bastante malo porque las advertencias son visibles desde lejos, por lo que es una fuga de información sobre la contraseña).

    
respondido por el Thomas Pornin 28.10.2012 - 18:09
fuente
2

@Yoav Aner lo ha determinado totalmente sobre el impacto de la seguridad de almacenar tanto el hash de la contraseña como el hash del candado de la contraseña. Además, @ cx42net tiene una sugerencia brillante: use Javascript en el lado del cliente para verificar si está activado el bloqueo de mayúsculas, y si es así, avise al usuario.

No tengo nada que agregar a esas respuestas, así que permítanme tratar de expandir un enfoque diferente (inspirado en una sugerencia de @Yoav Aner). Para esto, necesito saber si el bloqueo de mayúsculas funciona mediante el uso de mayúsculas en todas las letras que escribe, o si funciona invirtiendo el caso de todas las letras que escribe. Parece que la respuesta depende del cliente en particular, así que te daré una respuesta en ambos sentidos; es posible que deba aplicar ambos, si no está seguro sobre qué tipo de sistema está utilizando el cliente.

Si Capslock marca con mayúsculas todas las letras: Almacene solo el hash de la contraseña en su base de datos. Cuando reciba una contraseña de candidato P del cliente, puede realizar los siguientes pasos en el servidor para validar la contraseña:

  1. Compute Hash (P) y vea si coincide con el hash de la contraseña del usuario (como se almacena en la base de datos). Si es así, marque el usuario como autenticado; ya terminaste De lo contrario, continúe con el paso 2.

  2. Comprueba si P tiene letras minúsculas en ella. Si es así, rechace el intento de autenticación. Si no (si todas las letras en P están en mayúsculas), rechace el intento de autenticación, pero advierta al usuario que verifique si tiene el bloqueo de mayúsculas activado y pídale que intente nuevamente.

Este esquema ciertamente no afecta negativamente la seguridad del sistema de ninguna manera.

Si capslock invierte el caso de todas las letras: Almacene solo el hash de la contraseña en su base de datos. Cuando reciba una contraseña de candidato P del cliente, puede realizar los siguientes pasos en el servidor para validar la contraseña:

  1. Compute Hash (P) y vea si coincide con el hash de la contraseña del usuario (como se almacena en la base de datos). Si es así, marque el usuario como autenticado; ya terminaste De lo contrario, continúe con el paso 2.

  2. Deje que P 'denote el resultado de invertir el caso de todas las letras en P. Compute Hash (P) y vea si coincide con el hash de la contraseña del usuario (como está almacenado en la base de datos). En caso afirmativo, marque el usuario como autenticado pero adviértales que compruebe si tienen activado el bloqueo de mayúsculas. De lo contrario, rechace el intento de autenticación.

Este esquema reduce el esfuerzo necesario para un ataque de adivinación de contraseña en línea en un factor de 2; no es un gran trato. No reduce la seguridad del sistema contra ataques sin conexión en absoluto.

Anexo: esta es una idea loca que puedes probar si el bloqueo de mayúsculas mayúsculas todas las letras. No lo recomiendo, pero lo menciono solo porque es una locura.

Almacene solo el hash de la contraseña en su base de datos. Cuando reciba una contraseña de candidato P del cliente, puede realizar los siguientes pasos en el servidor para validar la contraseña:

  1. Compute Hash (P) y vea si coincide con el hash de la contraseña del usuario (como se almacena en la base de datos). Si es así, marque el usuario como autenticado; ya terminaste De lo contrario, continúe con el paso 2.

  2. En este punto, va a probar la hipótesis de que tal vez P sea la versión de bloqueo de la contraseña del usuario. Compruebe si P tiene letras minúsculas. Si P tiene letras minúsculas, rechace el intento de autenticación y deténgalo. De lo contrario, continúe con el paso 3, donde continuará probando esta hipótesis.

  3. Intentarás desbloquear P en mayúsculas y luego verificar la versión con mayúsculas. Desafortunadamente, hay muchas formas posibles de desbloquear el bloqueo de P, así que tendrás que probarlas todas. En particular, suponga que P tiene letras en las posiciones n , con todas esas letras en mayúsculas. Pruebe todos los 2 subconjuntos n de esas posiciones. Para cada subconjunto, digamos que P 'denota el resultado de tomar P y luego en minúsculas solo las letras en ese subconjunto de posición; calcular Hash (P '); compruebe si Hash (P ') coincide con la contraseña hash del usuario; si lo hace, marque al usuario como autenticado y adviértale que desactive el bloqueo de mayúsculas; de lo contrario, continúe con el siguiente subconjunto. Si ningún subconjunto es exitoso, rechace el intento de autenticación.

Esto es bastante loco, por todo tipo de razones. Reduce bastante la seguridad de los ataques de adivinación en línea (por un factor de 2 n , para las contraseñas con letras n en ellas). No reduce la seguridad de los ataques de adivinación fuera de línea. Pero también aumenta significativamente la complejidad del servidor. Y dadas las mejores respuestas que se mencionan en otros lugares, parece que no hay razón para usar este esquema loco.

    
respondido por el D.W. 10.05.2012 - 08:21
fuente
1

No creo que esto sea necesario y, además, puede reducir la seguridad de su aplicación.

Para la parte necesaria, no sé cómo identifica a su usuario, pero si se trata de una autenticación de cliente / servidor y el cliente le envía la contraseña en claro al servidor (el servidor, luego, la contraseña de hash para comparar con la base de datos), puede consultar las mayúsculas aquí:

// in the server :
// $password contains the original, clear password
$up_pass = invertcase($password); // I'll explain invertcase later
if (hash_and_find_pwd_in_db($password) == null) {
    if ($up_pass == $password) {
        return "Did you have caps lock enabled?";
}

(Nota de seguridad: la seguridad del esquema anterior asume que implementas hash_and_find_pwd_in_db() mediante el uso de la contraseña y el comparando con un valor hash almacenado en la base de datos. De esta manera, tu base de datos solo almacena los hashes de las contraseñas, no las contraseñas de texto simple.)

Siempre se puede verificar usando javascript si el bloqueo de mayúsculas está habilitado , pero nuevamente, si JS está deshabilitado, esto no funcionará.

Sobre el rendimiento: Imagina que tienes una versión "mayúscula", una versión "minúscula", etc. Tendrá que verificar la contraseña original que se encuentra en el código correcto, contra la correcta, si no la encuentra, tendrá A ella la base de datos tantas veces como alternativas tengas. Solo para que el usuario sepa que lo que ingresó no es válido por una razón específica. Estoy seguro de que no es eficiente en absoluto.

Ahora, como dijo @Yoav Aner, escribir aXbJklMP en el modo de bloqueo de mayúsculas resultará en esta cadena: AxBjKLmp . Eso significa que tendrás que implementar una función invertcase que cambie el caso de cada letra para que coincida con el modo de bloqueo de mayúsculas hipotéticas, sin ninguna certeza.

Sobre la parte segura, @Yoav Aner respondió perfectamente :)

    
respondido por el Cyril N. 10.05.2012 - 07:58
fuente

Lea otras preguntas en las etiquetas