Página de contraseña segura olvidada: ¿es viable una implementación sin servidor?

8

Esta es otra pregunta "¿Cómo se hace correctamente una página de contraseña olvidada"? Sin embargo, aborda explícitamente dos opciones de implementación que he encontrado recientemente.

Los enfoques comunes [1,2] que conozco se basan en un token aleatorio que solo se puede usar una vez y que tiene una validez limitada:

  • Las visitas de los usuarios olvidaron la página de contraseña
  • El usuario proporciona la dirección de correo electrónico (o similar)
  • Si el correo electrónico está asociado con una cuenta de usuario válida
    • La aplicación genera un token único y aleatorio. t es de suficiente entropía (digamos 128 bits).
    • La aplicación almacena el token aleatorio t y la marca de tiempo en la que se creó junto con el usuario en la base de datos
    • La aplicación envía un correo electrónico que contiene un enlace para restablecer la contraseña a la dirección de correo electrónico de los usuarios. El enlace es similar al siguiente: enlace
  • El usuario hace clic en el enlace del correo electrónico
  • La aplicación comprueba
    • si hay un token t dentro de la base de datos para un usuario determinado
    • en caso afirmativo, comprueba que sigue siendo válido en función de la marca de tiempo almacenada
    • en caso afirmativo, permite al usuario acceder a la página de contraseña de restablecimiento
  • El usuario establece una nueva contraseña
  • Después de eso, la aplicación invalida el token t

Puedes agregar un poco más de cosas de seguridad como canales fuera de banda o preguntas de seguridad. Pero para mí, esa es la mejor práctica común que conozco.

Ahora considere un enfoque diferente. Perderemos la propiedad de un solo uso. Sin embargo, el beneficio es que la aplicación no tiene que realizar un seguimiento de los estados del token en absoluto.

En lugar de generar un token aleatorio, usaremos un HMAC de la siguiente manera:

  • token = HMAC_k (correo electrónico, marca de tiempo)

k es un secreto que la aplicación conoce de suficiente entropía. El enlace de restablecimiento que se envía por correo electrónico al usuario tiene el siguiente aspecto:

Cuando el usuario accede al enlace, la aplicación lo verifica de la siguiente manera:

  • calcule HMAC según los parámetros de la URL: token_calculated = HMAC_k (correo electrónico, marca de tiempo)
  • compruebe si el token proporcionado como parámetro de URL y el HMAC calculado coinciden
  • en caso afirmativo, compruebe si el token sigue siendo válido según la marca de tiempo
  • en caso afirmativo, permita que el usuario acceda a la página de contraseña de restablecimiento

En mi opinión, la propiedad de no tener que mantener un estado del lado del servidor es más valiosa que la propiedad de un solo uso. Esto supone que se configura una validez razonable y corta de tokens en el lado del servidor, por ejemplo, de 20 a 30 minutos.

Realmente me gustaría saber qué piensan otras personas del segundo enfoque. Especialmente, si hay algún inconveniente que podría no haber notado todavía.

[1] enlace

[2] enlace

    
pregunta user32387 17.02.2015 - 10:57
fuente

2 respuestas

7

Su pregunta está bien escrita y entiende claramente los problemas. No hay nada fundamentalmente incorrecto con el enfoque de token de criptografía que describe. Algunas cosas a tener en cuenta:

  • La mayoría de los sitios en estos días son intensivos en la base de datos, por lo que almacenar un token de restablecimiento de contraseña es una sobrecarga adicional.
  • Debe limitar la cantidad de correos electrónicos de restablecimiento de contraseña que se pueden generar (por ejemplo, un máximo de 2 por 30 minutos, para cada dirección de correo electrónico), lo que requiere escribir en la base de datos.
  • Eres dependiente de que k permanezca en secreto; esto podría ser copiado por un administrador malintencionado (o forzado brutalmente, si es débil), mientras que los tokens de la base de datos evitan este único punto de falla.
  • Una debilidad común (aunque menor) con los esquemas de restablecimiento de contraseña es la fuga del token a sitios externos en el encabezado del remitente. Hacer que el token sea estrictamente de un solo uso puede ayudar con esto, aunque también puede corregir esta debilidad con tokens criptográficos.

Hay una opción similar con la generación de cookies de sesión: usando crypto o la base de datos. De hecho, las consideraciones de rendimiento son mucho más importantes para las cookies de sesión, ya que este trabajo se realiza para cada solicitud. A pesar de la sobrecarga, la mayoría de los sitios usan tokens de base de datos, por las ventajas de seguridad menores.

    
respondido por el paj28 17.02.2015 - 11:32
fuente
0

No es necesario perder la propiedad de una sola vez. Imagine que el token de restablecimiento de contraseña es (conceptualmente, agregue detalles): HMAC (correo electrónico, marca de tiempo, current_password_hash) , donde el hash de la contraseña actual es el hash que almacena en su base de datos (con suerte basado en algún KDF) y esta es la contraseña que el usuario no conoce.

Cuando el usuario cambia la contraseña, el valor de este hash será diferente, y por lo tanto el token ya no será válido. Incluso si el usuario establece la misma contraseña (aunque es poco probable, como deberían haberlo intentado), la implementación correcta del hashing de la contraseña debe incluir un nonce, y el hash de la contraseña será diferente después del restablecimiento, aunque la contraseña sea la misma. Básicamente, esto se basa en el hecho de que ya almacenas algún estado en la base de datos (el hash de la contraseña) y puedes omitir el almacenamiento de otro.

P.S. k realmente debería permanecer en secreto, esta es una gran preocupación :)

    
respondido por el Petar Donchev 04.05.2017 - 15:39
fuente

Lea otras preguntas en las etiquetas