We are implementing self password reset on a web application, and I know how I want to do it (email time limited password reset URL to users pre-registered email address).

My problem is that I can't find any references to point the developers at around using that technique. Can anyone point me in the direction of some good references on this technique?


8 Answers 8


Some suggestions:

Don't reset the user's password until confirmed. Don't immediately reset the user's password. Only reset it once the user clicks on a confirmation link sent to their pre-registered email address.

Require a CAPTCHA. When a user requests that their password be reset, force them to solve a CAPTCHA before proceeding any further. This is to prevent automated tools from trying to give many users grief, and force the user to prove they are a human (not a robot).

Randomness. The time-limited password reset URL should include a random, unguessable component. Make sure you use crypto-quality randomness. The output from /dev/urandom or System.Security.Cryptography.RNGCryptoServiceProvider would be a good choice. The output from rand() or random() or System.Random are not random enough and would be a bad choice. A GUID or timestamp is not random enough and would not be a good choice.

Include a time limit. The reset confirmation link should expire after some reasonable time: say, 24 hours. The link should be usable only once, and should immediately expire as soon as it is used.

Include explanatory text in the email. You may want to add some explanatory text to the email, to explain why the email was sent, in case someone requests a reset for an account that is not your own. You could include some text like "Someone has requested that the password be reset for your account username on site. If you made this request, click here to change your password. If you did not make this request, click here to cancel the request."

Send email after the password is reset. Once the password is successfully reset, send email to the user to let them know that the password has been changed. Don't include the new password in that email.

Monitor cancellations. You might consider including some logic to monitor the frequency with which users click the cancellation link indicating that they didn't request a reset. If this goes above a certain threshold, it might be useful to send an alert to the system operators. Also, if a cancellation link for some request is visited after the confirmation link is visited, that's a potential indication of an attack against that user -- you may want to take action at that point, e.g., invalidate the user's password and require them to reset their password again. (This is a defense against the following attack: the attacker gains access to the user's mailbox, then requests that their password on your site be reset, then visits the confirmation link. If the attacker doesn't delete these emails from the user's inbox, then when the real user reads their email, they may click the cancellation link, giving you an indication of possible trouble.)

Use HTTPS. The link should use https (not http:), to protect against various attacks (e.g., Firesheep attacks on users surfing the web from an Internet cafe).

Log these operations. I suggest logging all such requests. In addition to logging the user's username, you may want to log the IP address of the client that requested a reset link be emailed to the user, as well as the IP address of the client that visited the reset link.

Additional reading. You may also want to read Troy Hunt's excellent blog post, Everything you ever wanted to know about building a secure password reset feature. Thanks to @coryT for a link to this resource.

Lastly, consider non-password authentication. Passwords have many problems as an authentication mechanism, and you might consider other methods of authenticating users, such as storing a secure persistent cookie on their machine with an unguessable secret to authenticate them. This way, there is no password to forget and no way for the user to be phished, though you do need to provide a way for a user to authorize access from a new machine or a new browser (possibly via email to the user's pre-registered email address). This survey paper has an excellent survey of many fallback authentication methods and their strengths and weaknesses.

  • 3
    +1, also note that though it is popular (as evidenced by most of the wrong answers on this SO question ), a GUID is not random enough. Also, I would just add a throttling mechanism, i.e. a user cannot request to reset his password e.g. 3000 times in one hour.
    – AviD
    Commented Jan 30, 2011 at 8:19
  • To summarize my conversation with @avid at his answer to that question, I'd say a version 4 GUID is indeed mostly random, and I'd guess it is long enough. But it is probably silly and a bit dangerous to use since it was not originally designed for the task. And who knows where your code will be ported next?
    – nealmcb
    Commented Jan 30, 2011 at 21:31
  • 3
    "Don't include the new password in that email." If you have the user's password in clear text, you're doing it wrong. Commented Jul 19, 2012 at 21:38
  • 1
    @DavidMurdoch, 64-80 bits should be plenty for the random part. (40 bits would actually probably be enough for this purpose, but why take any chances?)
    – D.W.
    Commented Jul 21, 2012 at 0:49
  • 1
    @DavidMurdoch See the link I posted above for more on D.W.'s answer (i.e. that a nonce of 64 bits is probably fine for this purpose): How long should a random nonce be? - IT Security
    – nealmcb
    Commented Jul 26, 2012 at 16:13

Troy Hunt has a very nice write-up on this exact question. Everything you ever wanted to know about building a secure password reset feature

  • 2
    troy's blog is a great resource for all things related to web security Commented Jul 19, 2012 at 23:01

OK, so your question is, how should you structure the password/account recovery process? That will depend on what you want to optimize for: hassle-free user experience or good security.

If you want good security:

  • During signup, the user must enter his email address.
  • During signup, the user must enter a secondary channel for authentication -- mobile phone number or challenge question & answer (i.e. "what's your mothers maiden name" or better).

  • During recovery, your system first gets a rough verification of identity by means of the above secondary channel -- the challenge question, or by SMS'ing a code to the mobile phone, or similar.

  • When the first identity check above is cleared, the system sends a password reset email to the previously entered email address only. This is an additional, important measure to prevent f.x. Sarah Palin type exploits.

  • The email must not contain a new password or similar. It should have a click-able link to an HTTPS encrypted webpage on your site which a) is linked to the account via a non-guessable secret value provided in the URL, b) is time-limited, so the account recovery only works for x hours after it was requested, c) provides a way for the end user to create a new password.

  • Have good logging on all account reset transactions, and have a human being actually monitor these and act if they appear suspicious (look at the server logs for the IP addresses fx, do many requests come from the same IP address, are there instances were a user is trying to reset passwords from a country different from the registered account owner's etc).

You can also sidestep this complexity altogether: It's still early days, but OAuth / OpenID / sign in via Facebook, Google etc removes this complexity entirely from your systems, but with a perhaps less well established usability.

  • 2
    Challenge questions are the opposite of security. Commented Jul 19, 2012 at 21:27
  • @DavidMurdoch: can you provide a reference that discusses this? I'd like to read more on it. Commented Jul 20, 2012 at 10:46
  • @David Murdoch : The challenge questions are password equivalent -- but the key question is to what. In my scheme they unlock a password reset mechanism which (presumably) isn't under the attackers control; the original email address. But true, password reset mechanisms generally trade reduced security for increased usability, perhaps I should have made that more clear.
    – user2122
    Commented Jul 20, 2012 at 10:58
  • Note that here in the dazzling future world of 2015, using a phone number as part of an MFA scheme has sort-of fallen apart, as the same small losable device serves as a gateway to both email and SMS.
    – Pointy
    Commented Apr 3, 2015 at 17:01

Any place that can send you a password means that they don't hash the password, but store it where it's somehow decryptable to 'plaintext'. This by itself is bad.

Probably not "most" secure, but more secure would be to:

Upon password request, send a password reset link to user with embedded GUID. The session in the GUID expires in, hmm, hour or so.

  • Yeah no issues with it as I have session protected from SQL injection, so I send mail with well randomised password reset session code and allow hour to change it, that's OK. Commented Jul 23, 2012 at 17:40
  • 1
    @AndrewSmith - You should allow the user to select the new password not send it to them, as already explained, if your able to send the password to the user there is something broken about your security model.
    – Ramhound
    Commented Jul 23, 2012 at 18:47
  • This website currently generates a NEW password, sends by email, hash it and store in db, which is not good I believe. Commented Jul 23, 2012 at 18:52
  • generating a password and not expiring it on next connection is indeed a bad idea. Commented Jul 23, 2012 at 19:01
  • 1
    If this GUID is in plain text, then it can be obtained with sql injection and then you are defeating the whole purpose of password hashing. This post is a dangerous suggestion by means of ambiguity.
    – rook
    Commented Jul 23, 2012 at 19:38

Another one which may or may not be appropriate for your application, but is used in online banking applications and similar types of thing is to send half the reset code by SMS messaging to a registered mobile phone. From an attacker's perspective this is a complete PITA as it requires compromise of a couple of channels in order to break.


The most secure way to perform a password reset is to generate a large random unique one-time reset token, with an expiry date, tied to the user ID. The token should be hashed in the database, since an attacker with SQL access could use it to reset arbitrary user passwords.

A reset link should be sent to the email address, containing the reset token. When the user clicks the link, the token's hash should be found in the database, and the expiry date verified to be in the future. If these conditions are met, the user should be presented with a screen that allows them to type in a new password.

This entire process must be done over SSL, otherwise an attacker might sniff the URL and reset the password before the user does.

A few other tips:

  1. Secret questions a minor annoyance to attackers and a major annoyance to users. Avoid them completely.
  2. Present the user with a human verification challenge (e.g. a CAPTCHA) before sending the password reset. This prevents automated reset requests.
  3. Check whether the IP address performing the reset is one that has successfully logged into the account previously. If it's not, ask some further details about the account / user, e.g. account creation year, birth date, first line of address.
  4. Add an "I didn't ask for this email" link, so that users can report erroneous password reset requests.
  • Even if it is generated via SSL: you have no insurance that the e-mail itself is transferred over SSL and so this method has a huge flaw in transit -- the basic flaw of e-mail relay and retrieval. Commented Jul 23, 2012 at 22:19
  • 1
    @EvanCarroll "the basic flaw of e-mail relay and retrieval." regarding email retrieval: it is the responsibility of the user to use an email recovery address from an email provider with POPS, IMAPS, or HTTPS webmail support (and most email providers offer all three nowadays).
    – curiousguy
    Commented Jul 24, 2012 at 13:06
  • @EvanCarroll Whilst it's not an ideal situation, security is always secondary to usability. If you implement the world's most secure browser login, but it requires JavaScript, Flash, Java, ActiveX, Silverlight, and a degree in Computer Science to use, your users will switch off. Email is the de-facto standard for this kind of functionality, primarily because it's usable by everyone. The burden of security on a user's email system and personal network is not with me, nor should it be.
    – Polynomial
    Commented Jul 24, 2012 at 13:38
  • 3
    @EvanCarroll The argument for the status quo is that there is no acceptable alternative.
    – curiousguy
    Commented Jul 24, 2012 at 19:20
  • 1
    I agree with your answer, but why would you include the user-id into the link? If for example this user-id is an 8 character number, these 8 characters are equally easy to guess, as 8 additional random characters in your token. With the random characters you would not expose the user-id though. Commented Jul 24, 2012 at 20:25

2 factor authentication via SMS ! 1 you know the customer and their mobie number, SMS them a unique code to add to the website to validate it is them :)

  • 1
    That's not necessarily a 2 factor solution, but it is out-of-band.
    – AviD
    Commented Apr 20, 2011 at 23:40
  • Until someone steals their phone. Commented Feb 3, 2014 at 13:10

Make it a few steps procedure. For example something like this:

  1. User forgots his password. He clicks "I forgot my password send me an email what to do next" button (button label may differ ;))
  2. Your server sends him a link www.yourdomain.com/lostpassword?param_1=x;param_2=y
  3. He clicks the link and is able to create himself a new password
  4. He clicks submit. Everything done. Everybody happy

One and only catch is in point 3). X and Y values should be random, unpredictable and connected to this one particular account. They should be also one time use only and should become stale after a short period of time (24 hours?). Store both values in a dedicated table with the corresponding columns:

| some_id | user_id | X | Y | expire_time

If a user tries to use proper link check whether expire time is not met and if not, allow him to change the password.

  • How is this any different to the other answers? There's no benefit in having both X and Y, just use a single random value.
    – Polynomial
    Commented Jul 24, 2012 at 15:09
  • OK cool, but how it's secure agaist SQL Injection? Is it because of dedicated table? Commented Jul 24, 2012 at 18:35
  • @Polynominal one value is easy to break via brute force attack. Commented Jul 24, 2012 at 18:47
  • 1
    @AndrewSmith you prevent yourself from an sql injection in a complete different way. It's how you filter user input and how you pass it to your queries. Commented Jul 24, 2012 at 18:48
  • 1
    @AndrzejBobak: Two values are equally as easy to break through brute-force as one value double the length of either. Commented Feb 3, 2014 at 13:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .