Autenticación segura: extensión parcial de la clave del lado del cliente ... revise / critique mi idea

5

Estoy tratando de averiguar cuál sería el sistema de autenticación "perfecto" para un sitio web.

Por un lado, sabemos que los algoritmos simples de hash pueden ser forzados por la fuerza bruta o agrietados de otras maneras. De ahí que ya no se recomiende MD5. Parece que la mejor solución para el almacenamiento seguro de contraseñas es hacer uso del estiramiento de las teclas en combinación con la salazón (es decir, usar PBKDCF2, bcrypt o scrypt). Para aquellos que no lo han escuchado, el estiramiento clave implica que un algoritmo de hash se computará a través de muchas iteraciones (no solo una vez), lo que hace que cada esfuerzo de fuerza bruta tome un tiempo irrazonable para calcular.

Ahora, hacer que los usuarios se registren, autentifiquen o cambien su contraseña, y que el servidor use la extensión de la clave para guardar la contraseña garantiza la protección adecuada de la contraseña, pero deja la puerta abierta para los ataques DoS. Principalmente, un pirata informático podría simplemente inundarlo con intentos de autenticación con contraseñas aleatorias, y el servidor se ahogaría al computar todas esas iteraciones para todos esos intentos.

Estoy tratando de obtener lo mejor de ambos mundos: almacenamiento seguro de contraseñas con el estiramiento de las llaves, sin que se abra la puerta DoS. Esta es mi idea y quiero saber si estoy supervisando algo, o si hay algún problema en mi lógica ... a veces, cuando estás muy cerca del problema ...

La idea es:

  1. CLIENT-SIDE: el usuario del sitio web ingresa un nombre de usuario, contraseña

  2. CLIENT-SIDE: el sitio web utiliza una solicitud de AJAX al servidor para recuperar el salt y la cantidad de iteraciones adjuntas al registro del usuario (según la coincidencia de nombre de usuario)

  3. LADO DEL CLIENTE: Paso de autenticación 1. El sitio web computa, en la computadora del cliente con Javascript, todas las iteraciones de hash MENOS UNO (explicaré por qué más adelante). El cálculo se realiza utilizando un algoritmo conocido, como PBKDF2, bcrypt o scrypt. El sitio web envía el resultado al servidor.

  4. LADO DEL SERVIDOR: Paso de autenticación 2. El servidor recibe el nombre de usuario + contraseña con hash (menos una iteración). Realiza la última iteración (con PBKDF2, bcrypt o scrypt) Compara con el valor almacenado para determinar si la combinación es correcta. Devuelve la respuesta al sitio web.

Ahora, ¿por qué todas las iteraciones menos una? Si un pirata informático obtiene una copia de la base de datos, y el servidor espera que se proporcione una contraseña con un hash completo, sería equivalente a almacenar las contraseñas en texto sin formato. Hacker copiaría y pegaría el hash y usaría el servicio de autenticación. Como tal, no podemos devolverlo directamente.

Sin embargo, como teóricamente no podemos "revertir" el hash, el hecho de que el servidor solo acepte un hash iterado n-1 significa que el pirata informático no puede adivinar cómo era la iteración anterior, según lo que vemos en la base de datos. ¿Es eso correcto?

Al final, tenemos la mayoría del trabajo realizado en el lado del cliente (el servidor solo realiza una iteración), eliminando la amenaza DoS, pero también tenemos las contraseñas almacenadas con el estiramiento de teclas completo con sal, una La práctica más segura.

¿Me estoy perdiendo algo? ¿Sería esta una forma ideal de implementar un sistema de autenticación? ¡Házmelo saber! Me pregunto si me estoy perdiendo algo aquí ...

    
pregunta hbCyber 27.09.2013 - 07:17
fuente

4 respuestas

4

El hashing del lado del cliente funciona, conceptualmente. El problema, sin embargo, es el de power . En un contexto web, el cliente usa Javascript, y Javascript es débil para las tareas intensivas de computación. El cliente ya utiliza un sistema que puede tener una CPU relativamente pequeña (podría ser un teléfono inteligente barato, por ejemplo), pero Javascript agrega su propia sobrecarga, que es enorme (porque se interpreta, difícil de JIT , y carece de tipos de enteros decentes). Como estimación aproximada, el hashing del lado del cliente en Javascript será 20 a 40 veces más lento que el hashing de contraseña en un servidor decente.

Desafortunadamente, la paciencia del usuario no se estira; El usuario tolera uno o dos segundos de retraso, no más. Por lo tanto, cuando utiliza el hashing del lado del cliente, tiene que usar menos iteraciones que cuando usa el hashing del lado del servidor, lo que debilita todo el panorama.

O, dicho de otro modo, siempre que maneje el proceso de inicio de sesión de no más de veinte usuarios por segundo , el hashing del lado del servidor le permitirá usar más iteraciones que el hashing del lado del cliente, y por lo tanto, ser mejor para la seguridad.

Si el cliente usa un applet de Java , es mucho más poderoso; el factor "20x" se convierte en "3x". Pero los applets de Java han pasado de moda y no funcionarán en tabletas y teléfonos inteligentes. Los clientes móviles con una aplicación dedicada pueden reactivar el concepto de hash de contraseña del lado del cliente.

En cuanto a los detalles , la mejor manera no es "eliminar una iteración" del algoritmo, sino agregar un hash adicional: los algoritmos criptográficos son animales complejos, y aunque la función de hashing de contraseñas se usa internamente "iteraciones", no necesariamente utilizan solo iteraciones. Por ejemplo, no puede eliminar fácilmente "la última iteración" de bcrypt y obtener un resultado parcial para ser transmitido al servidor. Entonces, en su lugar, realice todas las iteraciones en el cliente, envíe el resultado R al servidor, y el servidor almacena tanto el salt como el h (R) para alguna función hash h (por ejemplo, SHA-256).

    
respondido por el Thomas Pornin 27.09.2013 - 13:11
fuente
2

SRP ya permite el estiramiento de la clave del lado del cliente porque tiene un KDF del lado del cliente. Si lo desea, puede pasar 15 minutos quemando ciclos mientras estira su clave, cada vez que inicia sesión, sin afectar el rendimiento del servidor.

Este es solo uno de muchos de sus beneficios.

    
respondido por el nly 27.09.2013 - 17:30
fuente
0

Un defecto que puedo ver es que, como está haciendo la iteración n-1 en el lado del cliente, el uso de bcrypt / scrypt / PBKCDF no tiene sentido. Debido a que el uso de estos algoritmos es hacer que el craqueo de contraseñas consuma mucho tiempo y que el cómputo sea intensivo. En el escenario actual, un atacante tendrá el hash de iteración n-1 fácilmente disponible y además requerirá solo otra iteración 1 para adivinar la contraseña. Lo cual sería trivial para cualquier atacante y, según mi conocimiento, realizado en una simple máquina de escritorio.

Una posible solución para evitar el DoS es que, si alguien (usuario malintencionado) desea iniciar sesión en la cuenta, luego de un cierto número de intentos puede detener al usuario para que inicie sesión durante cierto tiempo y siga aumentando este tiempo de manera exponencial. Por ejemplo, deje que los intentos de umbral sean 3. Si un usuario con el nombre de usuario 'user123' está ingresando, (s) ingresa 3 contraseñas incorrectas, luego puede bloquear la cuenta durante 5 segundos. Si nuevamente se produce un intento incorrecto después de 5 segundos, puede bloquear las cuentas durante 10 segundos y así sucesivamente.

De esta manera, se asegura de que un usuario no esté acaparando su recurso y haciendo que cualquier ataque de fuerza bruta consuma tiempo y, finalmente, sea inviable.

EDITAR: Otro problema con este enfoque es que está enviando la sal al lado del cliente. La sal se utiliza para dificultar el forzoso de las contraseñas. En el escenario actual, el atacante también tendrá la sal correspondiente al nombre de usuario fácilmente disponible.

Además, si el cliente desactiva el javascript, entonces él / ella no podrá iniciar sesión en el sitio web. Pero esto puede no ser un problema importante, ya que los sitios web modernos dependen en gran medida de los javascripts y requieren que se habilite en el cliente.

    
respondido por el Jor-el 27.09.2013 - 09:36
fuente
0

Con una función de derivación de clave lenta, desea alcanzar dos objetivos:

Evita que un atacante pueda iniciar sesión

El hash iterado del lado del cliente, puede verse como un reemplazo de contraseña en sí mismo, que se envía al servidor y se vuelve a hash y se almacena. Si un atacante puede encontrar este reemplazo de contraseña, podría iniciar sesión. Dado que la salida del hash pre-iterado (BCrypt) es de aproximadamente 60 caracteres (con 7 caracteres constantes y 21 caracteres de sal conocidos), todavía habría más de 1E50 combinaciones para probar, por lo que el forzamiento de los brutos parece impracticable.

Evita que un atacante obtenga la contraseña original, puede usarla en otros servicios web

Para averiguar la contraseña original, un atacante aún tendría que hacer todas las iteraciones. Por lo tanto, las iteraciones realizadas en el lado del cliente ralentizarán los ataques de diccionario (prueba de contraseñas de uso frecuente).

En realidad, su esquema parece funcionar, al menos no puedo ver un defecto evidente. Sin embargo, hay un problema con BCrypt, este algoritmo usa la contraseña original y el salt en cada iteración, por lo que no podría hacer una iteración más, en lugar de eso tendría que calcular un hash adicional en el servidor.

Por favor, lea también la respuesta de Thomas Pornin, hay razones prácticas para hacer el lado del servidor de hash (y él es el experto).

    
respondido por el martinstoeckli 27.09.2013 - 13:39
fuente

Lea otras preguntas en las etiquetas