¿Puedo usar el hash de contraseña de un usuario como la clave AES para crear un token de una sola vez?

4

Quiero crear un token de una sola vez que los usuarios usan para restablecer su contraseña. El token se debe invalidar una vez que se usa, ¿es seguro usar su contraseña de hash actual como la clave aes para cifrar el token de modo que una vez que la contraseña cambie, el token ya no se pueda descifrar? Este token solo se cifrará / desencriptará en el servidor.

¿Cuáles son las desventajas / ventajas de este enfoque?

    
pregunta JF6IX 17.12.2018 - 23:43
fuente

4 respuestas

2

El problema con el que se encuentra es que si el hash de la contraseña es todo lo que se necesita para generar un token válido, un atacante con un volcado de base de datos puede generar tokens de reinicio para todos (lo que en primer lugar anula el propósito del hashing de las contraseñas). ). Este problema se puede resolver, pero termina siendo mucho más complicado que usar valores aleatorios para restablecer tokens y almacenar sus hashes en una tabla.

Nota importante: yo mismo no lo implementaría sin un examen más detenido, solo se me ocurrió esto por encima de mi cabeza por el gusto de hacerlo. Dale a los demás la oportunidad de señalar lo que me equivoqué. En serio, ya lo arruiné una vez.

¿Qué propiedades necesita un token de restablecimiento de contraseña?

  1. Identifica un usuario específico y no es válido para nadie más
  2. Ya no es válido después de cambiar la contraseña
  3. Vence después de un tiempo
  4. Secreto y muy difícil de adivinar
  5. El volcado de la base de datos no le otorga a un atacante ningún token existente ni le permite generar tokens a voluntad

Ya que quieres tener tokens restablecidos sin tener que almacenarlos en una base de datos, sugeriría este psuedocode para la generación:

token = {
    "user": [username],
    "expiry": [unix timestamp]
}

// Very important!!!
// Password hash should be bcrypt or argon2 with good cost
// Secret application "pepper" is used to salt the key with HKDF, so a database dump won't allow generating reset tokens
key = hkdfsha256(user_password_hash, pepper)

return base64encode(token + hmacsha256(token, key))

Y para verificar:

data = base64decode(data)
token = data[:-32]
submitted_hmac = data[-32:] // last 32 bytes are hmacsha256
if (token['expiry'] > now()) {
    return false
}
// [retrieve password hash here]
key = hkdfsha256(user_password_hash, pepper)
return hmacsha256(token, key) == submitted_hmac

Examen

  1. El nombre de usuario identifica al usuario para el que está el token
  2. Derivar la clave HMAC a partir del hash de la contraseña significa que una vez que se cambie la contraseña, el token ya no será válido.
  3. La verificación de caducidad evita que un token no utilizado permanezca válido por mucho tiempo
  4. El hash y pepper de la contraseña hacen que la salida HMAC (y, por lo tanto, el token completo) no se pueda adiestrar.
  5. El uso de un pimiento para derivar la clave HMAC evita que un atacante con un volcado de base de datos genere tokens para todos

Pros

  • No hay almacenamiento en la base de datos
  • La validez del token está intrínsecamente vinculada a la contraseña actual
  • Todas las fichas válidas actualmente se pueden invalidar fácilmente cambiando el pimiento

Contras

  • Tamaño de token algo grande (108 caracteres base64 con un nombre de usuario de 15 caracteres), pero aún así debería estar bien para una URL en un correo electrónico.
  • El token no es completamente opaco, los usuarios pueden ver la información de vencimiento y del usuario. Esto no afecta la seguridad, pero si desea evitar las preguntas molestas de las personas que piensan que es un problema, también podría cifrarlo, aunque esto significa agregar un IV (si lo hace, debe cifrar antes de HMAC).
  • Si un atacante obtiene un volcado de base de datos y el pimiento, puede generar tokens a voluntad.
  • No hay forma de saber cuántos tokens válidos existen en un momento dado, o para qué usuarios.

Algunos pensamientos

  • Usar el hash de la contraseña completa significa que la sal formará parte de la clave HMAC, por lo que ya debería contener una gran cantidad de entropía, incluso si la contraseña es terrible y el pimiento se expone. Para atacar este esquema, tanto la base de datos de pimienta como tendrían que estar expuestas.
  • Si realmente desea reducir el token, puede truncar la salida HMAC a 16 bytes, terminar el nombre de usuario en nulo y hacer username + 5 byte unix timestamp + 16 byte HMAC . Esto evita el problema 2038 con la marca de tiempo, y con un nombre de usuario de 15 caracteres se ha reducido a 52 caracteres base64. Sin embargo, no recomendaría hacer la marca de tiempo de 5 bytes, los 3 bytes adicionales no parecen valer la pena.
  • Dado que la cantidad de espacio que está ahorrando es estrictamente más pequeña que la tabla de usuarios que ya está almacenando, no creo que valga la pena. Tal vez si no pudiste alterar el esquema de la base de datos y no tenía una forma de almacenar un token de reinicio.
respondido por el AndrolGenhald 18.12.2018 - 23:46
fuente
1

Un inconveniente importante es que no se puede limitar el tiempo.

Imagine que el usuario solicita un restablecimiento pero nunca lo usa, ya que recuerda la contraseña. En este punto hay un token con una vida útil hasta que la contraseña cambie.

Sería mejor generar un token único por cada intento de reinicio utilizando cualquier medio seguro. Ponga esto en una tabla de base de datos separada con un vencimiento.

Puntos de bonificación para monitorear si se usan tokens de reinicio antiguos, ya que esto podría indicar actividad sospechosa (si se combina con otras señales).

    
respondido por el David 18.12.2018 - 00:36
fuente
1

Lo que describe no contiene una fecha de caducidad intrínseca, por lo que seguirá siendo viable hasta que se cambie la contraseña (y / o la sal). Por supuesto, puede insertar una fecha de caducidad en el texto claro que está cifrando junto con otros datos interesantes sobre la solicitud de restablecimiento.

Si bien es muy poco probable que se rompan tanto el cifrado de aes como el hashing de la contraseña, necesitaría dedicar algo de tiempo a pensar si este riesgo muy pequeño fue superado por el beneficio de usar esto como la clave del costo de generar una clave de alguna otra manera (por ejemplo, una clave aleatoria) y de almacenarla / indexarla, y por supuesto, marcarla como usada / reemplazada. Mi primera reacción fue no, pero cuanto más lo pienso, más elegante parece, por ejemplo. no debe haber ningún riesgo de un ataque de Oracle de relleno si está utilizando hashes de contraseña medio decentes.

Asegúrese de utilizar el hash de contraseña y no los otros datos almacenados en el atributo. Necesita una respuesta de alguien que sepa mucho más sobre criptografía que yo si hay una necesidad de un vector de inicialización, pero si la carga útil es menor o igual que el tamaño del bloque de encriptación, no lo hago. Piensa hay algún beneficio. Tenga en cuenta que, si espera que el usuario escriba el texto completo (no puede truncarlo con texto sin formato variable) todavía está viendo más de 20 caracteres de galimatías (sin una IV).

    
respondido por el symcbean 18.12.2018 - 00:54
fuente
1

Esto es algo para lo que se inventó un sistema como PBKDF2 o RFC2898, en combinación con el ajuste de clave. Están diseñados para recibir información del usuario y devolver cadenas basadas en hash sólidas que puede usar tal como está para verificar las contraseñas, pero también para operaciones adicionales como material clave. No es la única opción y se están poniendo en uso más sistemas (y diferentes) para hacer esto en este escenario.

Consulte la derivación de clave basada en contraseña y el ajuste de clave para obtener más información. Y como siempre con crypto: no hagas tu propia , sino que utiliza una biblioteca bien probada.

Para su caso específico (use un token para restablecer una cuenta): ¿hay un caso en contra de generar un token aleatorio? La razón para usar algo como AES sería el cifrado reversible con la misma clave que se usó para cifrarlo, lo que no parece ser un caso de uso aquí.

    
respondido por el John Keates 18.12.2018 - 03:42
fuente

Lea otras preguntas en las etiquetas