Recuperar contraseña - Ayuda guía

eXtreM3

Buenas de nuevo! Me siento un poco mal por abrir dos hilos en dos días pero necesito hacerlo xD :P

Me he visto con la necesidad de desarrollar la funcionalidad "¿Has olvidado tu contraseña?" en mi web con registro de usuarios. Pero no sé muy bien cómo hacerlo... He visto cómo lo hacen otras páginas, pero no tengo muy claro todo el proceso, sería algo así:

  1. Usuario entra en recuperar.php
  2. Usuario rellena email y solicita la nueva
  3. Se envía email de confirmación al correo con un enlace
  4. Si usuario hace clic en dicho enlace, se genera una contraseña aleatoria y se actualiza la base de datos, enviando un nuevo email al usuario con su nueva contraseña.
    4.1 Si usuario no hace clic, pues obviamente no ocurre nada.

A ver... umm... tengo lagunas xD, el enlace es la clave de todo el asunto, no sé cómo hacerlo para que sea invulnerable / lo más seguro posible.

Obviamente no me valen soluciones tipo: recuperar-password.php?idUsuario=14

He visto que en algunas webs utilizan la palabra "token" seguida de una combinación de letras y números muy largos (supongo que alguna encriptación) en plan:

token=523sadb13AKBCds0381dadsb

He googleado y no he sacado nada en claro, en los foros panchitos no dicen más que tonterías xD

Alguien es tan amable de guiarme?? Graciasssss

Buffoncete

está claro que el token debe ser algo que sólo tú sepas, por ejemplo.

Si quieres recuperar el id del usuario 34, que tiene nombre JUAN y email JUAN@email.com, puedes codificar en md5 todo lo siguiente.

token.id.34.usuario.JUAN.email.JUAN@email.com

al hacer el md5 te dará un string que sólo tú sabrás el valor xq lo tendrás guardado en la base de datos de usuarios y sólo tendrás que hacer un select por ese campo, aunque el md5 lo has de generar con información estática + la que pides para recuperar la contraseña.

PD: No es buena idea generar el md5 cada vez que entren en esa página xq si tu página web tiene 30.000 usuarios por poner un ejemplo, tendrás que generar 30.000 md5 y comparar, si te están haciendo un "flood" la página y el servidor acabarán cayendo, realizar un md5 no es "rápido", así que compensa tenerlo como campo en la BBDD.

PD2: Puedes guardar reglas en el servidor para generar el string que genera el md5 y que vaya cambiando cada semana, con un script que se ejecute en paralelo, actualizas el campo en la BBDD como "mantenimiento", que para 30.000 usuarios puede tardar entre 10 y 30 minutos, dependiendo el lenguaje y el motor de la BBDD.

Por ejemplo.

RULE: "email"+email;
RULE: "todoestoesunlio"+email;
RULE: "Ax48Zlks82095ldkañdl"+email+"dkwlZ3lksl@13ld.com";


GamA

Hace tiempo yo administraba un servidor de wow muy importante a nivel nacional (esto lo digo porque quiero decir que tenía muchos miles de usuarios :S) e implementé algo similar para la recuperación de contraseñas.

Lo que hice fue generar un md5 aleatorio (sin user ni nada), añadir en la base de datos dicho md5 asociado a la cuenta del jugador (el que pide el cambio de contraseña). Le mandas un correo y le das la ruta www.tuhost.com/recuperar.php?cod=<el md5>. Cuando el usuario clica puedes asegurarte de que ha venido alertado por el correo y por tanto es el poseedor del email y de la cuenta. Entonces allí le puse dos campos, password y repetir password, las teclea y sobreescribes su pass antigua (hasheada logicamente).

Créeme que es mejor que dejes al usuario poner su password, siempre será más fácil que no la olvide.

De esta forma que te digo, ni aunque alguien sepa su login y email podrá conocer la URL (la cual se genera de forma dinámica y jamás se repetirá para el mismo usuario). Sino un usuario que deje su cuenta abierta y alguien lea su email podría apuntar la dirección y usarla en el futuro para un cambio de contraseña (lo cual supongo que no desearás).

Ah, se me olvidaba. Logicamente cuando el usuario cambia su contraseña el md5 asociado a su cuenta lo borras para que esa URL no tenga sentido y por tanto no pueda nadie volver a usar ese código.

Por otro lado y para no dejar suciedad en la DB pusimos un procedimiento en MySQL que se activaba a las 00:00 con el crontab de linux para hacer un delete de las peticiones de password del más de 1 día de antiguedad, así si alguien pide cambio y luego no lo efectua tu no tienes basura en la DB.

Yo también en su día tuve el dilema de como hacer esto de forma segura y funcionó a prueba de miles de decenas de miles de usuarios durante varios años :).

#2 Nosotros teníamos más 170.000 usuarios y jamás nos dio problemas, dado que a la vez solo pedian el cambio unos 30 aproximadamente, lo cual no da inconveniente alguno. El verdadero problema es dar siempre la misma URL por lo que comenté, si alguien se hace con ella...

Para acabar con el flood es tan sencillo como poner la PK de la tabla la cuenta que solicita el cambio de pass, de esa forma no regeneras nada, así fue como evitamos nosotros que se pidiera más de un cambio de contraseña al día

#1 Si no te quedó claro algo dilo y lo explico más detalladamente.

eXtreM3

Muchas gracias tío, qué crack. A ver voy a repetir los pasos un poco esquematizados para ver si se me han quedado las ideas claras:

  1. Genero un campo md5 de un string aleatorio, asociado a la id de un usuario -> será un campo único para cada id para evitar el flood.
  2. Cuando un usuario pide el cambio, le mando una url con dicho md5
  3. En esa página el usuario escribe su contraseña 2 veces y se guarda encriptada.
  4. Se borra el campo del string aleatorio md5 para que pueda volver a generarlo si desea.
  5. Aunque no se active el enlace, en 1 día se pasa un script para borrar la basura.

Muy interesante, muchas gracias de verdad ;)

LR

#4 el funcionamiento es parecido (sino igual) al que usarias para generar una activacion de cuenta por mail.

Fyn4r

Justo estos días estaba pensando en algo como esto, gracias #1 por abrir el thread y #2 y #3 por las explicaciones, lo tengo bastante claro ahora :D

Una cosa que se me ocurre, en mis tiempos de C, usaba la hora para generar semillas, etc.
Entonces estaba pensando en si sería buena idea crear una cadena aleatoria con "hora_actual + user_id + algun_otro_campo" o algo de este estilo.

edit: bue, acabo de ver que en PHP ya existe una función para generar randoms, me callo xDD

GamA

#4 De nada hombre, para eso estamos :)

#5 Exactamente fue esa la forma de la que implementé la creación de cuentas. Muy similar para verificar el correo del usuario.

#6 Si, existe para generar randoms en PHP, no te compliques tampoco :P.

Usuarios habituales

  • GamA
  • Fyn4r
  • LR
  • eXtreM3
  • Buffoncete