Forgot Password Cheat Sheet



{| style="padding: 0;margin:0;margin-top:10px;text-align:left;" |- Last revision (mm/dd/yy): // = Introduction =
 * valign="top" style="border-right: 1px dotted gray;padding-right:25px;" |

This article provides a simple model to follow when implementing a &quot;forgot password&quot; web application feature.

= The Problem =

There is no industry standard for implementing a Forgot Password feature. The result is that you see applications forcing users to jump through myriad hoops involving emails, special URLs, temporary passwords, personal security questions, and so on. With some applications you can recover your existing password. In others you have to reset it to a new value.

= Steps =

Step 1) Gather Identity Data
Delete The first page of a secure Forgot Password feature asks the user for multiple pieces of hard data that should have been previously collected (generally when the user first registers). Steps for this are detailed in the identity section the Choosing and Using Security Questions Cheat Sheet here.

At a minimum, you should have collected some data that will allow you to send the password reset information to some out-of-band side-channel, such as a (possibly different) email address or an SMS text number, etc. to be used in Step 2. Display a generic response, whether the username is valid or not, indicated that a link has been generated and sent. This helps reduce the chance for username or email enumeration.

Step 2) Send a Token Over a Side-Channel
After step 1, lock out the user's account immediately. Then SMS or utilize some other multi-factor token challenge with a randomly-generated code having 8 or more characters. This introduces an “out-of-band” communication channel and adds defense-in-depth as it is another barrier for a hacker to overcome. If the bad guy has somehow managed to successfully get past steps 1 and 2, he is unlikely to have compromised the side-channel. It is also a good idea to have the random code which your system generates to only have a limited validity period, say no more than 20 minutes or so. That way if the user doesn't get around to checking their email and their email account is later compromised, the random token used to reset the password would no longer be valid if the user never reset their password and the "reset password" token was discovered by an attacker. Of course, by all means, once a user's password has been reset, the randomly-generated token should no longer be valid. Avoid sending the user's username in the same email as the password reset link.

Step 3) Verify Security Questions
Once the user clicks the reset link presented in Step 2, Step 3 should display at least two of the user’s pre-established personal security questions, along with input fields for the answers. It’s important that the answer fields are part of a single HTML form.

Do not provide a drop-down list for the user to select the questions he wants to answer. Avoid sending the username as a parameter (hidden or otherwise) when the form on this page is submitted. The username should be stored in the server-side session where it can be retrieved as needed.

Because users' security questions / answers generally contains much less entropy than a well-chosen password (how many likely answers are there to the typical "What's your favorite sports team?" or "In what city where you born?" security questions anyway?), make sure you limit the number of guesses attempted and if some threshold is exceeded for that user (say 3 to 5), lock out the user's account for some reasonable duration (say at least 5 minutes) and then challenge the user with some form of challenge token per standard multi-factor workflow; see #2, above) to mitigate attempts by hackers to guess the questions and reset the user's password. (It is not unreasonable to think that a user's email account may have already been compromised, so tokens that do not involve email, such as SMS or a mobile soft-token, are best.)

Step 4) Allow user to change password in the existing session
Step 4 requires successfully answering the questions in Step 3, and allows the user to reset his password. Display a simple HTML form with one input field for the new password, and one to confirm the new password. Enforce all password complexity requirements that exist in other areas of the application. As before, avoid sending the username as a parameter when the form is submitted. Finally, it's critical to have a check to prevent a user from accessing this last step without first completing steps 1 and 2 correctly. Otherwise, a forced browsing attack may be possible.

Step 5) Logging
It is important to keep audit records when password change requests were submitted. This includes whether or not security questions were answered, when reset messages were sent to users and when users utilize them. It is especially important to log failed attempts to answer security questions and failed attempted use of expired tokens. This data can be used to detect abuse and malicious behavior. Data such as time, IP address, and browser information can be used to spot trends of suspicious use.

= Other Considerations =


 * Whenever a successful password reset occurs, the session should be invalidated and the user redirected to the login page.
 * Strength of questions used for reset should vary based on the nature of the credential. Administrator credentials should have a higher requirement.
 * The ideal implementation should rotate the questions asked in order to avoid automation.

= Authors and Primary Editors =

Dave Ferguson - gmdavef[at]gmail.com Jim Manico - jim[at]owasp.org Kevin Wall - kevin.w.wall[at]gmail.com James McGovern - james.mcgovern[at]hp.com Wesley Philip - wphilip[at]ca.ibm.com James Jardine - james[at]jardinesoftware.com

= Other Cheatsheets =


 * }