How to Implement Password Resets?


Question

I'm working on an application in ASP.NET, and was wondering specifically how I could implement a Password Reset function if I wanted to roll my own.

Specifically, I have the following questions:

  • What is a good way of generating a Unique ID that is hard to crack?
  • Should there be a timer attached to it? If so, how long should it be?
  • Should I record the IP address? Does it even matter?
  • What information should I ask for under the "Password Reset" screen ? Just Email address? Or maybe email address plus some piece of information that they 'know'? (Favorite team, puppy's name, etc)

Are there any other considerations I need to be aware of?

NB: Other questions have glossed over technical implementation entirely. Indeed the accepted answer glosses over the gory details. I hope that this question and subsequent answers will go into the gory details, and I hope by phrasing this question much more narrowly that the answers are less 'fluff' and more 'gore'.

Edit: Answers that also go into how such a table would be modeled and handled in SQL Server or any ASP.NET MVC links to an answer would be appreciated.

1
81
5/23/2017 12:02:40 PM

Accepted Answer

Lots of good answers here, I wont bother repeating it all...

Except for one issue, which is repeated by almost every answer here, even though its wrong:

Guids are (realistically) unique and statistically impossible to guess.

This is not true, GUIDs are very weak identifiers, and should NOT be used to allow access to a user's account.
If you examine the structure, you get a total of 128 bits at most... which is not considered a lot nowadays.
Out of which the first half is typical invariant (for the generating system), and half of whats left is time-dependant (or something else similar).
All in all, its a very weak and easily bruteforced mechanism.

So don't use that!

Instead, simply use a cryptographically strong random number generator (System.Security.Cryptography.RNGCryptoServiceProvider), and get at least 256 bits of raw entropy.

All the rest, as the numerous other answers provided.

66
7/23/2018 12:56:37 PM

EDIT 2012/05/22: As a follow-up to this popular answer, I no longer use GUIDs myself in this procedure. Like the other popular answer, I now use my own hashing algorithm to generate the key to send in the URL. This has the advantage of being shorter as well. Look into System.Security.Cryptography to generate them, which I usually use a SALT as well.

First, do not immediately reset the user's password.

First, do not immediately reset the user's password when they request it. This is a security breach as someone could guess email addresses (i.e. your email address at the company) and reset passwords at whim. Best practices these days usually include a "confirmation" link sent to the user's email address, confirming they want to reset it. This link is where you want to send the unique key link. I send mine with a link like: domain.com/User/PasswordReset/xjdk2ms92

Yes, set a timeout on the link and store the key and timeout on your backend (and salt if you are using one). Timeouts of 3 days is the norm, and make sure to notify the user of 3 days at the web level when they request to reset.

Use a unique hash key

My previous answer said to use a GUID. I'm now editing this to advise everyone to use a randomly generated hash, e.g. using the RNGCryptoServiceProvider. And, make sure to eliminate any "real words" from the hash. I recall a special 6am phone call of where a woman received a certain "c" word in her "suppose to be random" hashed key that a developer did. Doh!

Entire procedure

  • User clicks "reset" password.
  • User is asked for an email.
  • User enters email and clicks send. Do not confirm or deny the email as this is bad practice as well. Simply say, "We have sent a password reset request if the email is verified." or something cryptic alike.
  • You create a hash from the RNGCryptoServiceProvider, store it as a separate entity in an ut_UserPasswordRequests table and link back to the user. So this so you can track old requests and inform the user that older links has expired.
  • Send the link to the email.

User gets the link, like http://domain.com/User/PasswordReset/xjdk2ms92 , and clicks it.

If the link is verified, you ask for a new password. Simple, and the user gets to set their own password. Or, set your own cryptic password here and inform them of their new password here (and email it to them).


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon