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:
-
CLIENT-SIDE: el usuario del sitio web ingresa un nombre de usuario, contraseña
-
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)
-
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.
-
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í ...