For my project I need a "forgot password" functionality. 

I am not quite sure how to implement this kind of functionality yet so I was hoping to find some "best practice" on the internet but couldn't find anything useful that treats every important aspect of this quite common feature.



My own thoughts about this are rather straight forward:

If a user wanted to change his password I could create a unique token uniqueTokenForTheUser attached to a "change password request" which would be essentially the identifier for my backend to tell if it was the right user who sent the request.

So for example I'd generate/send an email to user@example.com with a link

http://www.example.com/changePassword?token=uniqueTokenForTheUser


uniqueTokenForTheUser would be stored in a table that gets checked by a thread in a certain interval and removes the record once the token is expired in case the user did not actually change his password.

Although this sounds rather straightforward to me, I wanted to double-check if there were any "best practices" out there e.g. when it comes to generation and deletion of that particular token.

Any suggestions or references to articles/tutorials are welcome!



Additional links suggested by comments:


The definitive guide to form-based website authentication (Thanks to Krumia)


Use HTTPS only for this, and then we'll get onto details of implementation.

First of all you're going to want to protect against user enumeration.

That is, don't reveal in the page whether the user exists or not. This should only be disclosed in the email itself.

Secondly you will want to avoid referrer leakage. Ensure no external links or external resources are present on your target link. One way to mitigate this is to redirect after the initial link is followed so that the token is no longer in the query string. Be aware that if something goes wrong (e.g. your database is briefly down), and a standard error template is shown, then this may cause the token to be leaked should it contain any external references.

Generate a token with 128bits of entropy with a CSPRNG. Store this server-side using SHA-2 to prevent any data leakage vulnerabilities on your reset table from allowing an attacker to reset passwords. Note that salt is not needed. Expire these tokens after a short time (e.g. a few hours).

As well as providing the non-hashed token to the user in the email link, give the option for the user to navigate to the page manually and then paste in the token value. This can prevent query string values from being logged in browser history, and within any proxy and server logs by default.

Optionally you may want to make sure that the session identifier for the session that initiated the password reset is the one that followed the link. This can help protect an account where the attacker has access to the user's email (e.g. setting up a quick forward all rule with limited access to the email account). However, all this really does is prevent an attacker from opportunistically following a user requested reset - the attacker could still request their own reset token for the victim should they want to target your particular site.

Once the password has been reset to one of the user's choice, you will need to expire the token and send the user an email to let them know this has happened just in case an attacker has somehow managed to reset their password (without necessarily having control of their mail account) - defence in depth. You should also rotate the current session identifier and expire any others for this user account.
This negates the need of the user having to log in again, whilst also clearing any sessions ridden by an attacker, although some users like to have the site log them out so they get a comfort blanket of confirmation that their password has actually been reset. Redirecting to the login page also gives some password managers the chance to save the login URL and the new password, although many already detect the new password from the reset page. 

You may also wish to consider other out of band options for the reset mechanism and the change notifications. For example, by SMS or mobile phone alerts.
