Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

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?

share|improve this question
    
What programming language are you using? –  Mark Davidson Jan 27 '11 at 23:08
3  
See also a similar question on SO. –  AviD Jan 28 '11 at 8:28

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.

share|improve this answer
1  
+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 Jan 30 '11 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 Jan 30 '11 at 21:31
2  
"Don't include the new password in that email." If you have the user's password in clear text, you're doing it wrong. –  Adriano Varoli Piazza Jul 19 '12 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. Jul 21 '12 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 Jul 26 '12 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

share|improve this answer
1  
troy's blog is a great resource for all things related to web security –  Numina Solutions Jul 19 '12 at 23: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.

share|improve this answer
    
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. –  Andrew Smith Jul 23 '12 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 Jul 23 '12 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. –  Andrew Smith Jul 23 '12 at 18:52
    
generating a password and not expiring it on next connection is indeed a bad idea. –  Lucas Kauffman Jul 23 '12 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 Jul 23 '12 at 19:38

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.

share|improve this answer
2  
Challenge questions are the opposite of security. –  David Murdoch Jul 19 '12 at 21:27
    
@DavidMurdoch: can you provide a reference that discusses this? I'd like to read more on it. –  Marjan Venema Jul 20 '12 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. –  Jesper Mortensen Jul 20 '12 at 10:58

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.

share|improve this answer

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.
share|improve this answer
    
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. –  Evan Carroll Jul 23 '12 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 Jul 24 '12 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 Jul 24 '12 at 13:38
3  
@EvanCarroll The argument for the status quo is that there is no acceptable alternative. –  curiousguy Jul 24 '12 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. –  martinstoeckli Jul 24 '12 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 :)

share|improve this answer
1  
That's not necessarily a 2 factor solution, but it is out-of-band. –  AviD Apr 20 '11 at 23:40
    
Until someone steals their phone. –  Lightness Races in Orbit Feb 3 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.

share|improve this answer
    
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 Jul 24 '12 at 15:09
    
OK cool, but how it's secure agaist SQL Injection? Is it because of dedicated table? –  Andrew Smith Jul 24 '12 at 18:35
    
@Polynominal one value is easy to break via brute force attack. –  Andrzej Bobak Jul 24 '12 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. –  Andrzej Bobak Jul 24 '12 at 18:48
1  
@AndrzejBobak: Two values are equally as easy to break through brute-force as one value double the length of either. –  Lightness Races in Orbit Feb 3 at 13:11

protected by Joel Spolsky Jul 19 '12 at 21:12

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

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