0

If I send an email to a user's email address with a link to a password reset page, how do I authenticate the link? Should I store some randomly generated key in my database, and then add then to the link string? www.mydomain.com/passwordreset.html?key=abcd1234zz235 Then check this key against the stored key in the database?

If this is indeed the right approach, should I create some separate table to store these keys with their corresponding email? And if the answer to that is yes, then should I delete these keys after the user has reset their password to save space in my database?

Thank you in advance!

Apollo
  • 8,874
  • 32
  • 104
  • 192
  • Something I didn't see in any of the answers below is that you should **not** store the access key in plain text in the database. It should have exactly the same security as the user's actual password because it essentially is a password, which means you need to hash it with a secure hashing function (e.g. bcrypt). You will then have to send the user ID along with the access key to the user and store the ID and the hashed access key in the database. – Mike Oct 07 '12 at 00:45

4 Answers4

1

That is a pretty typical way of handling it. I usually will add a PasswordResetKey field to my user table.

Adam Plocher
  • 13,994
  • 6
  • 46
  • 79
  • and how do you handle a request for a password reset where the email address has not even been registered with xyz service? – Apollo Oct 06 '12 at 23:45
  • @Derek what do you mean? I don't think your question is clear. – Mahn Oct 06 '12 at 23:47
  • If a user decides to reset the password for the address adfjal;sfsadfasjfkl;safj;lkjsfl;ksajf;@gmail.com, most likely this address does not exist. If nobody owns the address and this email address is not associated with an account for my service, how should I handle this. – Apollo Oct 06 '12 at 23:51
  • @Derek tell the user "reset link was sent to your email address" but don't actually do anything if the email address/user is not found. – Mahn Oct 06 '12 at 23:55
  • @Derek it would in theory be nice to let the user know the email address doesn't exist, in case he forgets he didn't use that address, but in practice it's way too much info for an attacker. – Mahn Oct 06 '12 at 23:58
  • @Mahn ok thank you for the advice. And would you mind taking a look at my comment hakre below there? – Apollo Oct 07 '12 at 00:04
1

should I create some separate table to store these keys with their corresponding email?

Yes, I would do that.

And if the answer to that is yes, then should I delete these keys after the user has reset their password to save space in my database?

Not because of space but because the transaction has been finished.

You can not save space here btw. because you should keep a log entry of the password change event in the audit log.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • So I should not delete the records? Should I have each key-email pair timeout after a certain period, but keep the record? In other words, in my activation page, say www.mydomain.com/resetPassword.html I get the current time and only validate the reset if the creationDate of the key-email pair was x number of hours ago? – Apollo Oct 06 '12 at 23:54
  • @Derek I'd just store the active key and once it's used move it from the table to your logs, wherever you store them. – Mahn Oct 07 '12 at 00:11
  • @Mahn ok that makes sense. And finally, is it safe to send the user's email over email. So http://domain.com/reset?email=myemail@domain.com&key=dakjf;lsdfjv111adf24`ksaf so that I can reference the email to key with the information stored in the database in reset.php – Apollo Oct 07 '12 at 00:14
  • @Derek: You delete, because the transaction has been finished - as written in the answer. And yes, you should add a time column and expire the password reset action when it is unfinished after a certain period of time. E.g. run a janitor job via cron and expire all password resets older than 48 hours. Tell your users that the password reset is valid for 24 hours. – hakre Oct 07 '12 at 00:20
  • @hakre i think an easier way would be to store the creation date of the email-key pair, and whenever the activate.php link is pressed, it checks the current time with the creation time. If it's been more than 24 hours, re-direct to an error page. – Apollo Oct 07 '12 at 00:23
0

Yes, that would work. Personally I like to have the key be an encoded string based on their user data that I can then decode. For instance, I might take the string userid|password_hash|emailaddress, encode it and send it. Then, when receiving it, I can decode it and split the parts out. The User ID is used to search the database, and then the password_hash and email are verified and if it all checks out then I can continue.

That said, your solution is probably better because it means you know whether or not the reset was actually requested. Ultimately all that matters is that it's made hard to just guess.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 2
    That is terrible advice. If you include this kind of sensitive information in the link, *and* allow anyone to follow it whether a password reset was requested or not, you have coded yourself a big fat security problem. You are sending enough information around (unencrypted, mind you) for someone to take over that account. – tdammers Oct 06 '12 at 23:38
  • and how do you handle a request for a password reset where the email address has not even been registered with xyz service? – Apollo Oct 06 '12 at 23:40
  • Yes. You said "encode". Not "encrypt". I hope you know the difference. – tdammers Oct 06 '12 at 23:45
  • 2
    It's definitely a better idea to use a random token, store it and discard it once used. – Mahn Oct 06 '12 at 23:51
  • @Mahn please see my comment to hakre above, and give your input. It would be most appreciated... – Apollo Oct 06 '12 at 23:54
  • @tdammers If you want to be pedantic, I shall simply say that I encipher it and leave it at that. – Niet the Dark Absol Oct 07 '12 at 03:02
0

Take a look at this link, which might help you. Basically you have to create a table for password reset requests and generate a key which will identify the user, and the reset request itself.

Community
  • 1
  • 1
Lior
  • 5,841
  • 9
  • 32
  • 46