3

I'm going to implements password recovery in my authentication. I haven't put this together in a while and wondering if there is anything I ought to be aware of.

My idea at the moment is:

  1. User clicks "Forgot my password" to go the password recover page: a form with an email field
  2. They enter their email, and an email is sent to that address with a link and password recover token/key (MD5 string - it just needs to be somewhat random and long right?). An entry is also made in the password_recovery database table which ties that token to their account, and an expire date (1 hour?)
  3. They retrieve the email and click the link to take them to a password set page: two fields to enter their password, and confirm their password again.
  4. Done, please login again with new password

Does that seem OK? Anything changed over the years where this approach is no longer recommended?

UPDATE

Additions that I opted for:

  • I store the token in the database hashed. If a hacker we to be able to access the database table somehow, they wouldn't be able to use the stored tokens .. hopefully (hashed with sha256)
  • 4
    The MD5 hash of what? A purely random token would seem better. – 5gon12eder Feb 23 '16 at 5:43
  • 3
    You're storing the TOKEN => USERID mapping in a server-side table anyway so there is no information you have to encode into the token. Therefore, any determinism you use for creating it only makes it easier for an attacker to guess the token. md5(time() . $ip_address) in particular, would be pretty easy to guess. Don't do that. – 5gon12eder Feb 23 '16 at 5:56
  • 4
    A GUID (as opposed to a MD5 hash) would be more secure and way less likely to be guessed. – Adam Zuckerman Feb 23 '16 at 6:16
  • 3
    Only thing I would add is that don't, at any point on your website, own up to whether you recognise the email address or not. If you get a password request for an email you don't recognise the actions at the website should be the same as for one you do. You can reasonably send a different email (e.g. "not associated with an account, do you want to create one?"). Window for using the recovery link needs to be > 1 hour (speaking as someone who regularly has to go pull said links out of spam traps...) – Murph Feb 23 '16 at 9:06
  • 3
    "They enter their email, and an email is sent to that address with a link and password recover token/key", Wait! So If I have a login on your system, any random person can attempt to log in as me, say "I forgot my password," and you'll cheerfully send new login credentials to whoever it is? – Solomon Slow Feb 23 '16 at 16:31
6

Does that seem OK?

Yes, assuming emails are the primary form of authentication of your site.

Anything changed over the years where this approach is no longer recommended?

Not that I know of.

Here are some points that you need to take into consideration.

What type of feedback you will give the user

When the email does not exist, what will you say and do?

  • If you display a message like "Sorry, this email doesn't exist", you are effectively leaking information about who is or isn't in your database.
  • So instead, you can display a message along the lines of "If this email corresponds to a user account, you will get further instructions". This is more secure, but it might confuse your users ("why didn't I get the email?").
  • A third option is to always send an email, only with a different content if the email wasn't in your database. This opens up your form for abuse though, as anybody could type anybody else's email, and your emails would eventually be spammed.

If your system uses username, it might be better to ask for the username, not the email address. You send the recovery email to email address associated with the account, without disclosing it to the user.

How do you protect the process against abuse

  • It's easy to see how somebody can use this form to generate emails, and then use social engineering to incite a user to click the link (or worse, forward the email). Therefore, you should make it very clear in your email.
  • You need to protect this form against brute force one way or another. Some examples: no more than one active request per account (do no resend emails until the previous one expires), limited number of tries per IP addresses, throttling, CAPTCHA, etc.

The token

The token is really a One Time Password for a user account.

  • The token should be random and unpredictable, and stored in the database with an association to the corresponding user ID, and the timestamp. You do no need MD5, nor do you need to encode anything in the token. Example in PHP, for a 32 character token: bin2hex(openssl_random_pseudo_bytes(16));
  • The token must have a short life time. 1 hour seems a bit long for me, I assume if you forgot your password you want to recover it now, so 30 minutes is probably plenty, but honestly this is up to you. The point is to limit the token lifetime.
  • You must disable the token as soon as it has been used.
  • You should not have more than one active token per user at any given time. From an relational database point of view, it's easier to enforce this rule when using a (nullable) field in your users table, rather than a separate table.
  • I'm unsure as to the usefulness of hashing the reset token. From your database, the risk is already mitigated by the short lifetime, and one-time-only usage. The real risk is in the transport, as they are sent by email (unsecure), so they can be compromised then. But why not.
  • Excellent answer, thanks for taking the time to write. Most things here I'd considered but a few new things to think about too. – Martyn Feb 25 '16 at 1:07
  • Here is a question - what if someone does man-in-the-middle attack between the server to the email? Wouldn't it be better if after validating the email, the user will have to answer another question after clicking on the link? – user229807 May 25 '16 at 16:37
  • @VladGincher No not really, "security questions" hardly provides any additional security. Their answers are usually very easy to guess for an attacker. Besides, you would have to provide an additional process in case the users forgets the answer to his questions, so you're back to square one... Realistically, it's very unlikely that somebody intercepts the emails in the manner you suggest - and if it happens, it means your server is compromised and you have much bigger problems anyway. If you have very high security requirements, you should consider 2-factor authentication. – rlanvin May 27 '16 at 8:21
  • @rlanvin, that's exactly what I'm doing, I have 2 steps verification. I know security question isn't that secure, I'm talking about other question - I'm asking which. I'm just wandering, nowadays when everyone tries to be more secure then the other one, this place left behind. If the server is compromised it's a huge problem, but I'm not talking about it, but about man in the middle attack in between the server to the email provider, or direct attack on the email provider. I'm trusting Google, but no one uses it. And limiting registration only for specific email providers is a bad idea. – user229807 May 27 '16 at 8:30
  • @VladGincher if you are already doing 2-factor auth, then you really don't need an additional question for recovering the password, since the password alone is useless for signing in... So really, I don't see a realistic use case where this would bring additional security. But every project is different, so in the end it's up to you. – rlanvin May 27 '16 at 9:11
2

I would certainly look around to find out the latest and greatest encryption algorithms. There is a lot of debate over which one works best, but generally I've found that, among state of the art algorithms, the advantages between one or another are negligible. That said, I would certainly look at alternatives to MD5 such as SHA256, SHA512, RipeMD, or WHIRLPOOL. It's always a good idea to do your research and reaffirm that your encryption methods haven't become depricated.

Also, I didn't see anything in your question that included SALTing. That is definitely something you might consider implementing in order to provide that extra security for users who may implement passwords that are too easy for hackers to crack using dictionary attacks or hash tables.

One final thing (and I'm assuming you've considered this); I would certainly make sure the recovery email they enter into your Forgot-my-Password system actually matches the email you have on file for that user... and I might also include a security question just to be on the safe side.

  • 1
    Hi. Yes I do use a salt when storing the password. Also, I'm looking up the user by email address before sending the email with the reset link. Thanks for the suggestions anyway. – Martyn Feb 24 '16 at 7:44
  • Note that encryption algorithms (such as AES) and hashing algorithms (such as MD5 or SHA512) are two distinct things. Encryption algorithms are designed to produce unique and reversible output (though difficult to decrypt without the key). Hashing algorithms are designed to be one way and usually (possibly always) have potential for collisions (better hashing algorithms will have fewer collisions). Encryption is inappropriate for password storage, hashing algorithms should be used instead. – 8bittree Mar 18 '16 at 15:53
1

I don't know if this a general approach or if it is just my personal way/idea for such a problem, but I would do the following.

Take the client's IP, crypt it with any algorithm you like, but the result in the link as a token and put a time stamp in it.

Then the link is only valid for the client's IP and for a given time.

Now even a man in the middle attack isn't able to hijack the reset token.

You could also request the MAC address of the user, but in my mind this is mostly an overkill.

This is my personal approach of achieving a save modern reset token.

  • 5
    That assumes that I'm going to reset the password from the same location/device I requested the change - that the mail delivery will be immediate, that I can respond to said delivery immediately and that nothing has changed in the meantime. – Murph Feb 23 '16 at 10:54
  • That is correct, but who would want to request a reset link from another device or would want to wait so long till the IP changes? Maybe about 1% of all cases will be like this? maybe even more? But never it will be the main part. So in my mind, it would be not the best idea, to throw away a lot of security, build a heavy different system that is hackable around it, for just a tiny group. – Yosh Synergi Feb 23 '16 at 11:47
  • 2
    These are real and consistent use cases for me (not least because password resets seem to fall into spam filters). Pragmatically if you're using a mobile device then the IP change is highly likely and a lot of people use a mobile device. In the same context you can see that there might be a delay between requesting a change and being able to use the link and that you might change device - request reset on phone prior to getting in the car to drive home, respond to request at home on a device with a better keyboard. Easy to find common, realistic, cases. – Murph Feb 23 '16 at 12:02
  • 1
    I'm sympathetic, but then the only secure thing is to not be connected to the network and to not have users... you can work round almost any reasonable security so its about balance of risk not about absolute mitigation. – Murph Feb 23 '16 at 14:09
  • 3
    @YoshSynergi A really simple, reasonable case which unfortunately poses a problem to binding the password reset to an IP is this: 1. I click the password reset on my desktop machine and an email is sent to me 2. I use my smart phone to open the email and click the link, because it's convenient – Andy Hunt Feb 24 '16 at 9:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.