Cómo evitar que alguien adivine el token en un enlace para restablecer la contraseña

1

Actualmente tengo la siguiente configuración para el manejo de usuarios que olvidaron su contraseña.

  1. Un usuario escribe su dirección de correo electrónico y presiona el botón de contraseña olvidada.
  2. Busco el usuario que pertenece a esa dirección de correo electrónico y almaceno una nueva 'solicitud de contraseña olvidada' en la base de datos. El elemento de solicitud de contraseña olvidada tiene este aspecto:

    Guid ForgotPasswordRequestId;
    Guid UserId;
    DateTime ValidUntil;
    
  3. Genero un token para identificar la solicitud de contraseña olvidada al convertir el ForgotPasswordRequest Guid en una cadena Base64. El Guid es un Guid versión 4 (aleatorio, no basado en el tiempo o en la dirección MAC). Consulte este enlace de MSDN para obtener información sobre la implementación.

  4. Creo un enlace como www.example.com/account/ForgotPassword?token=TOKEN que se envía al usuario en un correo electrónico.

  5. Cuando alguien visita ese enlace dentro de las 24 horas, puede establecer una nueva contraseña para esa cuenta.

Creo que las posibilidades de que alguien adivine el token son pequeñas, ya que un Guid es un número de 122 bits (128 bits, menos 6 bits para la información de versión). Por lo tanto, un pirata informático debería intentar, en promedio, (2^122 / 2) tokens dentro de las 24 horas antes de tener éxito. Si mis cálculos son correctos, es 3 * 10^31 tokens por segundo, lo que estoy seguro de que mi servidor no puede manejar;). Además, el token que deben adivinar no está relacionado de ninguna manera con el usuario para el que desea restablecer la contraseña.

Sin embargo, ¿es correcto generar el token directamente desde un Guid generado? ¿Hay alguna forma de que usar un Guid y no un generador seguro de números aleatorios haga posible un ataque? ¿Hay algún otro problema en este esquema que lo haga inseguro?

He visto esta pregunta , aunque su relación no explica las mejores prácticas para generar el token.

    
pregunta Roy T. 10.09.2015 - 09:51
fuente

3 respuestas

4

Debes crear un token criptográficamente aleatorio para esto. Definitivamente, el tuyo no es lo suficientemente aleatorio y se podría adivinar mucho más rápido que el (2 ^ 122/2) que mencionas. La importancia de la aleatoriedad criptográfica ya se ha discutido muchas veces en este foro, por ejemplo, aquí .

Cuando mencione que está utilizando .net, eche un vistazo a ASP.Identity, que puede generar tokens para usted, utilizando DataProtectorTokenProvider . Si no está utilizando ASP.Identity (u Owin para el caso), también puede usar RNGCryptoServiceProvider para generar tokens aleatorios seguros. No estoy diciendo que no pudieras hacerlo tú mismo, pero es difícil .

Editar: si está hablando de un GUID (como lo menciona), puede leer esta respuesta :

  

Por otro lado, para identificar a un usuario de una aplicación de banca en línea (o, probablemente, incluso una función de restablecimiento de contraseña de un sitio donde la identidad es valiosa) los GUID son definitivamente inadecuados.

    
respondido por el Michael 10.09.2015 - 10:49
fuente
2

Puede incluir no solo el código, sino también el correo electrónico del usuario (el correo electrónico al que envía el enlace) en el enlace para restablecer la contraseña. Por ejemplo:

www.example.com/account/ForgotPassword?email=user%40example.com&token=TOKEN

Cada vez que alguien visita el enlace ForgotPassword , debe validar no solo el token y su fecha de caducidad, sino también la dirección de correo electrónico antes de restablecer la contraseña.

En este esquema, el atacante debería no solo adivinar el token sino también la dirección de correo electrónico del usuario para el que se ha generado.

    
respondido por el user44 26.02.2016 - 23:28
fuente
0

Para mejorar tu enfoque puedes

  • Use un fuerte ruido pseudoaleatorio en lugar de GUID
  • Limita la cantidad de veces que alguien intenta acceder a un enlace de restablecimiento para un usuario en particular, por ejemplo. a 5. Necesitaría agregar userId a la solicitud que envíe y una columna de conteo en la base de datos
  • Imponer el retraso antes del siguiente intento, por ejemplo, 1 segundo, 5 segundos, 60 segundos
  • Bloquee la dirección IP durante un tiempo breve si el número de intentos alcanzó algún recuento máximo. Esto puede ayudar con el ataque de DOS a pequeña escala.
  • use SSL para sus solicitudes, para que los usuarios no envíen nuevas contraseñas en forma clara
respondido por el oleksii 10.09.2015 - 15:37
fuente

Lea otras preguntas en las etiquetas