Restablecimiento de la contraseña: ¿ID de usuario y marca de tiempo firmados criptográficamente o valor generado aleatoriamente?

2

¿Cuáles son las ventajas y desventajas de las diferentes formas de manejar los enlaces de restablecimiento? Veo dos formas de manejarlos:

  1. Genere una cadena aleatoria, por ejemplo con uuid4. Guárdelo en la base de datos con el usuario y envíelo en un enlace al usuario. Cuando se complete y envíe el formulario, la cadena aleatoria será la carga útil y se comparará con el usuario. La cadena se elimina de la base de datos por lo que solo se puede usar una vez. También debe tener una fecha de caducidad.
    • Pros:
      • Simple y seguro
    • Contras:
      • Deben almacenarlo en la base de datos
      • Un usuario malintencionado puede causar escrituras en la base de datos utilizando repetidamente la función "Olvidé mi contraseña". Esto debería ser mitigado por una característica máxima de tokens por día y eso solo lo limita para una cuenta. Si se sobrescribe el token, el espacio de almacenamiento no importará, pero aún así podría costar dinero en forma de escrituras en la base de datos.
  2. Generando un token firmado. Desde el nombre de usuario o la identificación y una marca de tiempo, se genera un token firmado con una clave secreta. Este es el enlace enviado al usuario. Cuando el usuario envía, el token se descifra y el usuario y la marca de tiempo se recuperan y validan. El problema aquí es que puede reutilizarse, por lo que también debe almacenar la contraseña anterior en el enlace (sería un hash con sal). No me gusta la idea de poder reutilizarla, ¿y si se usa en una computadora pública? Entonces el usuario tiene que borrar el historial del navegador, mal!
    • Pros
      • No es necesario almacenar nada en la base de datos.
    • contras
      • ¿Más riesgoso? ¿Es una mala idea enviar la contraseña antigua, encriptada (hash salado) en el enlace? Si ya se almacenó "la última vez que se modificó", se podría enviar en su lugar sin escribir en la base de datos luego de la solicitud de restablecimiento.
pregunta Testare1 Testsson 06.01.2017 - 20:47
fuente

6 respuestas

2

Iría a la opción 1 en todo momento: desea asegurarse de que un token determinado solo se use una vez y no es posible hacerlo sin una entrada en la base de datos.

    
respondido por el crovers 06.01.2017 - 21:22
fuente
2

Cada uno es válido, siempre y cuando su valor aleatorio sea lo suficientemente aleatorio y la encriptación / firma utilice algoritmos apropiadamente sólidos. Ya has empezado a pensar en escenarios de problemas específicos. Te animo a continuar.

Si asumimos que existe el riesgo de que los valores sean predecibles (o posibles a la fuerza bruta) o alguna otra vulnerabilidad (limitada) en el sitio, el valor aleatorio tiene alguna ventaja. Dado que está almacenado en el servidor, también sirve para marcar que la cuenta está en un estado cambiante. Los ataques dirigidos al proceso de renovación solo serán efectivos contra lo que debería ser una pequeña proporción de las cuentas. Sin embargo, esto es mucho un caso de borde.

Un problema que he encontrado con el valor aleatorio es el siguiente: no puedo recordar mi contraseña, hago clic en el botón de reinicio, espero, no hay correo electrónico, por lo que vuelvo a hacer clic en el enlace. Cuando el correo electrónico de reinicio llega no funciona! (porque es desde el primer reinicio, y un segundo correo electrónico está en camino con el código actual). OTOH para bloquear un segundo intento de reinicio golpea el exceso de confianza. Quizás una solución pragmática sea un período refractario después del último restablecimiento en el que no se pueda realizar un reinicio adicional.

Otra consideración es que probablemente podría aguantar la transcripción de un UUID de mi dispositivo de mensajería a mi dispositivo de navegación (si por alguna razón no pudiera o no quisiera cortar y pegar entre ellos y no pudiera hacer clic) a través del dispositivo de mensajería) pero un mensaje cifrado y firmado será mucho, MUCHO más largo.

Con respecto al problema de la computadora pública: no creo que mucha gente use un MUA dedicado en un dispositivo de este tipo, por lo que el riesgo de una huella dactilar solo se presenta si un cliente de correo electrónico basado en la web usa mucho el almacenamiento en caché (¡erk! ) o el sistema de autenticación no utiliza TLS (¡erk!) o (y esto potencialmente se aplica a dispositivos no públicos) el terminal está comprometido. Yo esperaría que en la mayoría de los casos, al acceder al mensaje que contiene el token, el usuario lo respalde, y con la contraseña antigua incrustada en ese token, deje de ser reutilizable. Está bien insertar la contraseña hasted, hash en el token usando hashes y sales apropiadamente fuertes, pero me da una sensación incómoda. Solíamos pensar que 3DES y MD5 eran seguros. Pero hay alternativas al envío de la contraseña con hash para evitar repeticiones. Los datos solo representan el estado del registro de cuenta en un punto específico en el tiempo. Podría usar un número de versión o fecha. Pero eso significa escribir el lado del servidor de datos.

    
respondido por el symcbean 06.01.2017 - 22:03
fuente
1

Opción 1. Este es realmente el camino a seguir y una práctica bien conocida. Definitivamente quieres un tiempo limitado. También lea aquí: enlace

    
respondido por el John Opdenakker 06.01.2017 - 21:41
fuente
0

Una falla con el segundo enfoque (valor firmado / HMACed) es que crea un único punto de falla en su sistema de autenticación: si un atacante logra robar esa clave de firma / HMAC, está jodido. El atacante puede generar tokens de restablecimiento de contraseña válidos para cuentas arbitrarias.

Por lo general, es más fácil leer los datos de un servidor (un archivo arbitrario incluye errores, como las vulnerabilidades de entidades externas XML, son bastante comunes) o un sistema de compilación (si su código fuente no es lo suficientemente seguro, o alguien pone artefactos de compilación en Un FTP legible públicamente, o alguien compromete sus copias de seguridad, o algo así, que escribir en una base de datos (y si el atacante puede escribir su base de datos, ya está brindado; solo pueden restablecer las contraseñas directamente). Esto es parte de la razón por la que la rotación de claves es una buena idea, pero si alguien roba tu clave antes de que se gire, podría hacer un gran daño rápidamente.

    
respondido por el CBHacking 11.01.2017 - 10:44
fuente
0
  

Generando un token firmado. Desde el nombre de usuario o la identificación y una marca de tiempo, se genera un token firmado con una clave secreta. Este es el enlace enviado al usuario. Cuando el usuario envía, el token se descifra y el usuario y la marca de tiempo se recuperan y validan.

Está hablando de claves secretas, tokens "firmados" y "descifrado" (y más adelante, "sal") de una manera muy flexible que sugiere que es probable que implemente este error. Lo que querría usar en este caso es un código de autenticación de mensaje , por ejemplo HMAC-SHA256 , que es casi seguro que sus bibliotecas criptográficas ya admiten.

Es muy sabio estar atento a los ataques de repetición. Su idea de enviar el hash con sal de la contraseña actual como contexto, aunque no es bueno si se toma literalmente, va por buen camino. Lo que te falta es que no necesitas poner el hash en la URL porque ya lo estás almacenando ; todo lo que necesita poner en la URL es información que le permita a su servidor recuperar el hash de contraseña con sal cuando se haga clic en la URL de restablecimiento. El nombre de usuario para el que está restableciendo la contraseña probablemente haría el truco.

Aquí hay un bosquejo de una posible solución. Primero, necesitas un secret_key seguro. Una forma de hacer esto que puede ahorrarle muchos dolores de cabeza es usar claves efímeras , en lugar de tener una clave a largo plazo que se use durante mucho tiempo y que un atacante aún pueda hacer lo que haga. en cambio, es cuando se inicia el servicio de restablecimiento de contraseña:

  1. Selecciona un secret_key de 128 bits al azar. Esto solo se guardará en la memoria, nunca lo escriba en el disco o en la red.
  2. Seleccione un único startup_uuid . Usaría un número aleatorio o UUID.

Esto significa que el secret_key solo es válido durante la vida útil de un proceso de servicio de restablecimiento de la clave: cada vez que se reinicia, la clave se descarta y se genera una nueva. La ventaja de esto es que su servicio es mucho más resistente contra el robo de llaves. La desventaja es que los enlaces de restablecimiento generados antes de un reinicio no se validarán: el propósito de startup_uuid es detectar ese caso y manejarlo de manera amigable.

Cuando se le solicita una URL de restablecimiento de contraseña para username , el servicio de restablecimiento de contraseña hace esto:

  1. Elija una fecha y hora de caducidad para el enlace de restablecimiento, por ejemplo, 15 minutos después de la hora actual.
  2. Busque la entrada de la contraseña username de la solicitud y recupere su hash de contraseña actual con sal.
  3. Construya un mensaje delimitado inequívoco reset_data con los siguientes campos en algún orden fijo:
    • El proceso del servidor ' startup_uuid ;
    • El nombre de usuario de la solicitud;
    • La marca de tiempo de caducidad seleccionada;
    • Hash de contraseña actual del usuario.
  4. calcular reset_token = HMAC-SHA256(secret_key, reset_data)
  5. Construya una URL de restablecimiento con estos valores como parámetros. ( NOTA: el hash de la contraseña es no un parámetro en la URL de restablecimiento)
    • El nombre de usuario;
    • La marca de tiempo de inicio del servidor;
    • La marca de tiempo de caducidad;
    • El reset_token .
  6. Devuelve esa URL construida.

Cuando reciba una solicitud en el punto final de la URL para restablecer la contraseña:

  1. Si el startup_uuid de la solicitud no es igual al del servidor, entonces el servicio se ha reiniciado desde que se generó el enlace. Ya no tenemos el antiguo secret_key y, por lo tanto, no podemos verificar esa solicitud. El usuario tendrá que rehacer el proceso de restablecimiento de contraseña.
  2. Si la hora actual es posterior al valor de fecha y hora de caducidad de la URL, el enlace caducará, así que no lo acepte.
  3. Busque el hash de contraseña con sal para el nombre de usuario de la solicitud.
  4. Construya un mensaje delimitado inequívoco reset_data como arriba.
  5. Verifique que este mensaje reset-data coincida con el reset_token que se incluye en la URL. Asegúrese de hacerlo de manera segura con una comparación de igualdad de tiempo constante.
  6. Si la verificación tiene éxito, siga adelante y restablezca la contraseña del usuario.

Este protocolo tiene estas virtudes:

  • Las claves secretas son efímeras y solo se guardan en la memoria, por lo que incluso si alguien roba una clave, solo es bueno hasta el próximo reinicio.
  • El hash de la contraseña que se restablecerá se usa como entrada para HMAC. Si un usuario intenta restablecer una contraseña que ya se ha restablecido o modificado, la verificación del token de restablecimiento fallará.
  • A diferencia de su propuesta, la contraseña con hash nunca se revela.
respondido por el Luis Casillas 11.01.2017 - 03:42
fuente
0

Me inclino por la opción # 1 por los siguientes motivos:

  • Es compatible con más funciones de seguridad. Por ejemplo, el código de reinicio podría entregarse fuera de banda (por ejemplo, SMS). El código de reinicio podría estar etiquetado con la dirección IP o la información de geolocalización en su base de datos, y podría restringir las solicitudes de reinicio a la misma ubicación. Puede contar los intentos de reinicio y evaluarlos al cometer transacciones de alto riesgo. Etc.
  • Es más fácil de implementar. Si desea pasar un token en lugar de un código, el token no solo tendría que estar firmado sino también codificado de manera que pasará correctamente a través de firewalls de correo electrónico, sistemas DLP, proxies, etc. Una secuencia de caracteres incorrecta y su token podría ser bloqueado o destrozado por otras características de seguridad. Todo el tiempo que se trabaje con esos problemas podría dirigirse, en cambio, a centrarse en más mejoras de seguridad.

Si le preocupan demasiadas inserciones en la base de datos, simplemente restrinja a un usuario a un puñado de códigos sobre una base FIFO. Por ejemplo, GMAIL le restringe a 10 códigos de respaldo.

    
respondido por el John Wu 24.02.2017 - 22:00
fuente

Lea otras preguntas en las etiquetas