Generate secret code for password reset
Asked Answered
N

4

14

I'm doing a module which allow users to reset password. I noticed how most websites they provide a confirmation link which contain query string that has a unique hash.

My question is: How can I generate this unique hash each time the same user request forgot password? Should I store this hash in database and use it for verification later on? Will it be safe? Or should I create some sort of algorithm which generate one-time password? How can I generate a OTP?

Nonna answered 24/8, 2010 at 15:47 Comment(1)
Hi everyone, tks for the respond. Im freaking surprise by the speed of respond. WOW!! stackoverflow communities rocks!!Nonna
G
30

Yes, you should

  1. Generate a random reset token. See e.g. this answer.
  2. Store it in the database (possibly with an expiry time)
  3. Send e-mail to the user with the reset token.
  4. User visits the reset password page with the reset token in the query string.
  5. Check the database to see the user associated with the reset token and if the expiry time hasn't passed.
  6. If everything checks out, allow the user to reset the password and delete the reset token from the database.

There seems to be a lot a confusion about the generation of the reset token (or whatever you want to call it). Please read the answer I've linked to and don't reinvent the wheel with hashes and weak seeds.

Gittern answered 24/8, 2010 at 15:50 Comment(4)
additional recommendation : always hash the reset password before storing to database since it can also be used temporary as a user password (i mean it can give access to user account just as a regular user password).Toxemia
In this answer you say "generate a unique random reset password". This is either an incorrect approach or incorrect terminology. If I request a forgotten password -with your email address-, it should send you an email, with a random string (aka nonce or token) but your existing password should continue to work! This prevents me from denying you service just by knowing your username or account email. So no, don't ever generate an actual random password for the user, it's not a good approach. Only generate a random token.Jest
@Jest "reset password" doesn't mean "password that has been reset", but I get you mean, token or nonce are better options. I've edited the answer.Gittern
Can I use previous user's password (which is hashed) as that random token? (for the first step)? Actually I need that to pass it as a argument for that reset-url. Can I do that?Quinnquinol
L
3

Just using some hash function with user's ID, user's salt (you salt the user's password, right?) and pseudo-random data should be OK:

$pwd_reset_hash = hash ( 'sha256' , $user_id . $user_salt, uniqid("",true));

Store it in the DB (together with time of request) as the reset key for this user

 user_id  pwd_reset_hash  time_requested  
===========================================  
 123      ae12a45232...   2010-08-24 18:05

When the user tries to use it, check that the hash matches the user and that the time is recent (e.g. "reset code is valid for 3 hours" or something like that)

delete it from DB when used or expired

Lowis answered 24/8, 2010 at 15:51 Comment(7)
I'd advise against this. It's not as bad as time(), but it's still not secure. An attacker that measures the latency between him and the server can probably guess the hash at least 1 each 20-50 times.Gittern
At least use uniqid() in place of microtime...Kissinger
Hi both, I understand microtime can be used. But lets say if I were to do a request password module. User provide their valid email and the system sends a email with the confirmation link with query string that contains the userid and the hash. when user receives the email and click on the confirmation link, the system should bring them to the respective page and validate the hash correct? to check this hash again, how can I generate the same hash using microtime??Nonna
@Artefacto: Edited. With uniqid and a per-user hash, this shouldn't be trivially guessable now, right?Lowis
@Piskvor uniqid is not particularly good either. At least, if you use it, pass true to the "more entropy" parameter.Gittern
Huh? the third param to hash expects a bool, so passing uniqid to it is pointless. I'd personally do hash('sha256', uniqid($userid . $usersalt, true));Kissinger
@Gittern : what do you mean by "guessing the hash" ? do you mean guessing reset password hash by knowing user id, user password and salt ? can you elaborate a little bit ?Toxemia
G
1

The way to go is indeed generate some kind of random thing and storing it in the database. As soon as the password is changed you remove the relevant record from the table so that the link cant be used again.

  • Mail the url to the user, including the "token".
  • If the link is visited, check if the token exists, allow user to change password
  • Delete the token from the database.

As said already in the other responses, doing a SHA1 or an MD5 of the userid, combined with microtime and some salt string is usually a safe bet.

Graciagracie answered 24/8, 2010 at 15:53 Comment(3)
Hi Blizz, I guess storing in the database is a way to go. Thanks blizzNonna
1) The salt would better be big enough so it can't be guessed by several hashes through brute force 2) Is it that hard to use mt_rand each time? There's a function in PHP that creates cryptographically secure random numbers, why the hell would you be reinventing the wheel building a "home-made" random string generator with a cryptographically weak hash like MD5 seeded by weak seeds like microtime...Gittern
Well nobody says you can't combine all of those. I usually take the userId, 2 random numbers, microtime and some random string.Graciagracie
Q
0

1) To generate the unique hash, mix current-time, user-id and some salt (text). For example, if your website is mysite.com, then use this code:

 $hash = md5(time() . $userid . 'mysite');

This will create a nice hash.

2) Yes, store it in database.
3) Yes, as long as you expire the hash after a fixed period of time, it will be secure.
4) No, generating one-time password usually annoys users.

Quadruplicate answered 24/8, 2010 at 15:50 Comment(3)
No, it will not because it's predictable.Gittern
If he changes the salt considerably, then it will not be predictable. It's not necessary to use 'mysite' exactly.Quadruplicate
Hi all, Thanks for the very quick respond. I will go ahead with the database method =)Nonna

© 2022 - 2024 — McMap. All rights reserved.