Don't Reset My Password
Resetting a user's password can be a simple thing to do, providing you avoid certain pitfalls.
Don't tell me you don't know me
Not as common as it once was, but when the users enters their email to have it reset, don't tell them if they got it wrong. Some might call it bad UX, but I call it an unnecessary leak of information. It gives an attacker the tool to test if a user account exists on the system or not. Information is key to an attacker. Don't leak information if you don't have to.
Don't reset my password
Far too often I've reset my password on some website, and they have immediately changed it and emailed it to me. When an email is correctly entered, you should create a unique token an use that to reset the password later. If you change the password immediately, this effectively allows an attacker to lock any user out of their account. I guess this would be a type of denial-of-service attack.
Don't email me my password
Some websites take your old password and email it to you. First of all, if you store your passwords using industry standard methods, this should not even be possible.
Continuing on from not changing the password in the first place, don't send the generated password to the user. Email is an insecure channel and you should limit the amount of sensitive information you deliver over it.
Do email me a reset password token
So how do you do it correctly? You generate a unique, one-time only token which the user can use to change the password on your website.
Always hash the token
Because the token can change a password it can grant access to a user's account. Thus you must treat it with the same sensitivity as the password itself. Like you store your passwords with seeded hashes, so should you store reset password tokens using seeded hashes. The user who comes to your site will provide you with the token and all you have to do it check if the token is correct. At no point after emailing the token to the user do you need to know what the token is, thus you can hash it just like you do with passwords.
Let the token expire and only accept it once
I can't stress this enough. As soon as the user has used the token and reset their password, invalidate the token. Once used it should never be used again. Just delete it from the database. Likewise, any issued token should expire after a reasonable amount of time. The user is likely to use the token quite soon after asking for it. Hence you can set a low expiration time without disrupting the flow of the experience.
Don't use security questions
Finally a point of great annoyance to me. Many sites ask the user to provide security questions. We've all seen these, such as "What's your favourite sports team?" The flaw with this is they invite the user to do something we've spent years trying to get them not to do: use personal information in passwords. The answers provided allow the user to reset or otherwise recover the password, or identify themselves to customer service. They are a type of password in their own right. If users answer the question truthfully, it's likely that an attacker could find the answers independently. If they are capable of overriding the original password, they make the original password itself useless. Any system is only as secure as its weakest link, don't use security questions.
You know what my favourite sports team is? That's right, it's
SV%c>lDWb)Q<~z4*. I have a good feeling about them this year.