<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://wiki.owasp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sc00bz</id>
		<title>OWASP - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.owasp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Sc00bz"/>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php/Special:Contributions/Sc00bz"/>
		<updated>2026-04-24T11:47:55Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.27.2</generator>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=Forgot_Password_Cheat_Sheet&amp;diff=239223</id>
		<title>Forgot Password Cheat Sheet</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=Forgot_Password_Cheat_Sheet&amp;diff=239223"/>
				<updated>2018-04-02T07:28:35Z</updated>
		
		<summary type="html">&lt;p&gt;Sc00bz: /* Other Considerations */ Corrected successful password reset advice&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; __NOTOC__&lt;br /&gt;
&amp;lt;div style=&amp;quot;width:100%;height:160px;border:0,margin:0;overflow: hidden;&amp;quot;&amp;gt;[[File:Cheatsheets-header.jpg|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;padding: 0;margin:0;margin-top:10px;text-align:left;&amp;quot; |-&lt;br /&gt;
| valign=&amp;quot;top&amp;quot;  style=&amp;quot;border-right: 1px dotted gray;padding-right:25px;&amp;quot; |&lt;br /&gt;
Last revision (mm/dd/yy): '''{{REVISIONMONTH}}/{{REVISIONDAY}}/{{REVISIONYEAR}}''' &lt;br /&gt;
= Introduction  =&lt;br /&gt;
 __TOC__{{TOC hidden}}&lt;br /&gt;
&lt;br /&gt;
This article provides a simple model to follow when implementing a &amp;amp;quot;forgot password&amp;amp;quot; web application feature.&amp;lt;br&amp;gt; &lt;br /&gt;
&lt;br /&gt;
= The Problem =&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Steps  =&lt;br /&gt;
&lt;br /&gt;
== Step 1) Gather Identity Data or Security Questions ==&lt;br /&gt;
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 [https://www.owasp.org/index.php/Choosing_and_Using_Security_Questions_Cheat_Sheet#Step_1.29_Decide_on_Identity_Data_vs_Canned_Questions_vs._User-Created_Questions here].&lt;br /&gt;
&lt;br /&gt;
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 3.&lt;br /&gt;
&lt;br /&gt;
== Step 2) Verify Security Questions ==&lt;br /&gt;
&lt;br /&gt;
After the form on Step 1 is submitted, the application verifies that each piece of data is correct for the given username. If anything is incorrect, or if the username is not recognized, the second page displays a generic error message such as “Sorry, invalid data”. If all submitted data is correct, Step 2 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Because users' security questions / answers generally contains much less entropy than a well-chosen password (how many likely answers are there to the typical &amp;quot;What's your favorite sports team?&amp;quot; or &amp;quot;In what city where you born?&amp;quot; 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 #3, below) 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.)&lt;br /&gt;
&lt;br /&gt;
==  Step 3) Send a Token Over a Side-Channel ==&lt;br /&gt;
&lt;br /&gt;
After step 2, 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 &amp;quot;reset password&amp;quot; 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.&lt;br /&gt;
&lt;br /&gt;
== Step 4) Allow user to change password in the existing session ==&lt;br /&gt;
&lt;br /&gt;
Step 4 requires input of the code sent in step 3 in the existing session where the challenge questions were answered in step 2, and allows the user to reset his password. Display a simple HTML form with one input field for the code, one for the new password, and one to confirm the new password. Verify the correct code is provided and be sure to 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. Ensure the user changes their password and does not simply surf to another page in the application. The reset must be performed before any other operations can be performed by the user.&lt;br /&gt;
&lt;br /&gt;
== Step 5) Logging ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
= Other Considerations =&lt;br /&gt;
&lt;br /&gt;
* Whenever a successful password reset occurs, all other sessions should be invalidated. Note the current session is already authenticated and does not require a login prompt.&lt;br /&gt;
* Strength of questions used for reset should vary based on the nature of the credential. Administrator credentials should have a higher requirement.&lt;br /&gt;
* The ideal implementation should rotate the questions asked in order to avoid automation.&lt;br /&gt;
&lt;br /&gt;
= Authors and Primary Editors  =&lt;br /&gt;
&lt;br /&gt;
Dave Ferguson - gmdavef[at]gmail.com&amp;lt;br/&amp;gt;&lt;br /&gt;
Jim Manico - jim[at]owasp.org&amp;lt;br/&amp;gt;&lt;br /&gt;
Kevin Wall - kevin.w.wall[at]gmail.com&amp;lt;br/&amp;gt;&lt;br /&gt;
James McGovern - james.mcgovern[at]hp.com&amp;lt;br/&amp;gt;&lt;br /&gt;
Wesley Philip - wphilip[at]ca.ibm.com&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Other Cheatsheets =&lt;br /&gt;
&lt;br /&gt;
{{Cheatsheet_Navigation_Body}}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Cheatsheets]]&lt;/div&gt;</summary>
		<author><name>Sc00bz</name></author>	</entry>

	<entry>
		<id>https://wiki.owasp.org/index.php?title=Using_Rfc2898DeriveBytes_for_PBKDF2&amp;diff=187893</id>
		<title>Using Rfc2898DeriveBytes for PBKDF2</title>
		<link rel="alternate" type="text/html" href="https://wiki.owasp.org/index.php?title=Using_Rfc2898DeriveBytes_for_PBKDF2&amp;diff=187893"/>
				<updated>2015-01-12T14:21:02Z</updated>
		
		<summary type="html">&lt;p&gt;Sc00bz: /* Implementing PBKDF2 in .NET */ Never output more bits than the base hash function's size&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Password storage is a large topic in application security.  If a security failure occurs, and the database is stolen, the passwords of the users are some of the most important data stored. Given the state of contemporary authentication, they do not need to be stored in plain text, so they should not. A hashed representation of the password, using a contemporary encryption algorithm and process, is the accepted way to store a password in today’s systems. More information can be found in the Password Storage Cheat Sheet[https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet].&lt;br /&gt;
&lt;br /&gt;
=Common .NET password storage=&lt;br /&gt;
&lt;br /&gt;
In .NET, the SQL Membership[http://msdn.microsoft.com/en-us/library/6e9y4s5t(v=vs.100).aspx] or ASP.NET membership[http://msdn.microsoft.com/en-us/library/ms731049(v=vs.110).aspx] patterns are often used for identity. In a best case scenario passwords aren’t stored by the local application or a well-known and trusted system is used such as AD, Facebook, or ASP.NET Identity. In each of these cases, the password storage is either handled by the subsystem, or not handled by the application at all.  &lt;br /&gt;
&lt;br /&gt;
Sometimes, however, there is no choice but to store the password in the application using home grown code. When this is the case, it is upon the software developer to select and use the correct hashing algorithm and process for password storage. Hashing is the process of deriving a unique, repeatable value form a text input and salt. This prevents the storage of the password itself, thus protecting the password if the database is stolen.&lt;br /&gt;
&lt;br /&gt;
Hashes create unique values that cannot be reversed into their source values, however, brute force could potentially lead an attacker to the source values. As such, a key derivation function is often used to increase the work factor needed to create the representative value. Often this key derivitation function is PBKDF2, or the Password-Based Key Derivation Function 2[http://en.wikipedia.org/wiki/PBKDF2].&lt;br /&gt;
&lt;br /&gt;
=PBKDF2 basics=&lt;br /&gt;
&lt;br /&gt;
PBKDF2 uses a pseudorandom function and a configurable number of iterations to derive a cryptographic key from a password.  Because this process is difficult to reverse (similar to a cryptographic hash function) but can also be configured to be slow to compute, key derivation functions are ideally suited for password hashing use cases.&lt;br /&gt;
&lt;br /&gt;
The details of PBKDF2 are openly published, and the goal of this document is not to replicate that information.  Generally speaking, the function is one that accepts a pseudorandom function (such as SHA1), a salt, the number of iterations, the length of the resultant hash, and the text to be hashed. The goal is one of ‘key stretching’, making the overall process of generating or reversing the hash harder. The .NET Framework can abstract the details of the algorithm from the developer.&lt;br /&gt;
&lt;br /&gt;
=Implementing PBKDF2 in .NET=&lt;br /&gt;
&lt;br /&gt;
Microsoft’s .NET platform supports PBKDF2 out of the box.  Rfc2898DeriveBytes allows a developer to generate a key for a value using PDKDF2 without implementing the algorithm. Using a number of iterations and a salt, a developer can easily implement the key stretching hash then store that data in the database. &lt;br /&gt;
During registration, rather than storing the password entered by the user, you should store the password and salt. Guids provide a very strong salt, as while they are not cryptographically random, they are guaranteed globally unique.  Rfc2898DeriveBytes[http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes(v=vs.110).aspx] will generate a hash and return the derived key with the requested number of iterations. You need to store them both.&lt;br /&gt;
&lt;br /&gt;
Each base hash function sized block of output from PBKDF2 is iterated independently of each other. Using PBKDF2 for password storage, one should '''never''' output more bits than the base hash function's size. With PBKDF2-SHA1 this is 160 bits or 20 bytes. Output more bits doesn't make the hash more secure, but it costs the defender a lot more time while not costing the attacker. An attacker will just compare the first hash function sized output saving them the time to generate the reset of the PBKDF2 output.&lt;br /&gt;
&lt;br /&gt;
Here is an example of using the System.Security.Cryptography namespace in a simple method. It returns the salt and key in a pipe delimited string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
public static string HashPassword(string password)&lt;br /&gt;
{&lt;br /&gt;
    // Generate a random salt&lt;br /&gt;
    byte[] salt = Guid.NewGuid().ToByteArray();&lt;br /&gt;
    // Generate the hash&lt;br /&gt;
    Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);&lt;br /&gt;
    rfc2898DeriveBytes.IterationCount = 10000;&lt;br /&gt;
    byte[] hash = rfc2898DeriveBytes.GetBytes(20);&lt;br /&gt;
    //Return the salt and the hash&lt;br /&gt;
    return Convert.ToBase64String(salt) + &amp;quot;|&amp;quot; + Convert.ToBase64String(hash);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that a new Guid is generated for each request. Every record in the database has a stored key and salt.&lt;br /&gt;
&lt;br /&gt;
Another note is that related to the number of iterations. In the Password Storage Cheat Sheet, it is recommended to make the password generation process as slow as possible without negatively affecting the user experience. Here, we have set the iterations to 10,000 and should review that number every year.&lt;br /&gt;
&lt;br /&gt;
=Using the hash on login=&lt;br /&gt;
&lt;br /&gt;
When a user later logs in, rather than using the password to confirm authentication, you can use the hashing function to generate a hash with the stored salt rather than a generated salt. Then compare the hash with the stored hash. &lt;br /&gt;
&lt;br /&gt;
=Limitations=&lt;br /&gt;
&lt;br /&gt;
The built-in .NET implementation of Rfc2898DeriveBytes limits the user to one psudorandom function - HMAC with SHA-1. This is acceptable in most scenarios today, but in the future, a more complex hashing function may be required.&lt;br /&gt;
&lt;br /&gt;
The .NET Compact Framework does not support Rfc2898DeriveBytes.&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
* [https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet Password Storage Cheat Sheet]&lt;br /&gt;
* [http://msdn.microsoft.com/en-us/library/6e9y4s5t(v=vs.100).aspx SQL Membership]&lt;br /&gt;
* [http://msdn.microsoft.com/en-us/library/ms731049(v=vs.110).aspx ASP.NET Membership]&lt;br /&gt;
* [http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes(v=vs.110).aspx Rfc2898DeriveBytes]&lt;br /&gt;
* [https://crackstation.net/hashing-security.htm Salted Password Hashing]&lt;br /&gt;
&lt;br /&gt;
[[Category:OWASP .NET Project]]&lt;/div&gt;</summary>
		<author><name>Sc00bz</name></author>	</entry>

	</feed>