Difference between revisions of "Password Storage Cheat Sheet"

From OWASP
Jump to: navigation, search
(Undo revision 155694 by Jmanico (talk))
(48 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
= Introduction =
 
= Introduction =
  
This article provides guidance on how to properly store passwords in order to help prevent password theft. Passwords are usually stored for one of two reasons:
+
Media covers the theft of large collections of passwords on an almost daily basis. Media coverage of password theft discloses the password storage scheme, the weakness of that scheme, and often discloses a large population of compromised credentials that can affect multiple web sites or other applications. This article provides guidance on properly storing passwords, secret question responses, and similar credential information. Proper storage helps prevent theft, compromise, and malicious use of credentials.
 +
Information systems store passwords and other credentials in a variety of protected forms. Common vulnerabilities allow the theft of protected passwords through attack vectors such as SQL Injection. Protected passwords can also be stolen from artifacts such as logs, dumps, and backups.
  
# to authenticate someone to this system, or
+
Specific guidance herein protects against stored credential theft but the bulk of guidance aims to prevent credential compromise. That is, this guidance helps designs resist revealing users’ credentials or allowing system access in the event threats steal protected credential information. For more information and a thorough treatment of this topic, refer to the Secure Password Storage Threat Model here [http://goo.gl/Spvzs http://goo.gl/Spvzs].
# to authenticate this system or user to a target system.  
+
  
This article provides recommendations on how to safely store passwords in situation 1. In situation 2, the passwords should be encrypted wherever they are stored, but this cheat sheet does not address that particular situation.
+
= Guidance =
  
Passwords are frequently stored as clear text. Sometimes they are encrypted when they should instead be hashed. In either case, such passwords can be read directly by the database's administrator, super users or via data theft by SQL Injection. If encrypted, these same techniques may also allow the attacker to gain access to the decryption key as well. Database backup media is also vulnerable to password theft if these passwords are included on the backup. It is recommended that you avoid storing the clear text password or an encrypted version of the password. Instead they should be strongly hashed as described below.
+
==  Do not limit the character set or length of credentials ==
  
= Password Storage Rules =
+
Some organizations restrict the 1) types of special characters and 2) length of credentials accepted by systems because of their inability to prevent SQL Injection, Cross-site scripting, command-injection and other forms of injection attacks. These restrictions, while well-intentioned, facilitate certain simple attacks such as brute force.
  
Passwords are secrets that only the account owner should know. For the system that uses these passwords to authenticate its users, there is no reason to decrypt them under any circumstances. It is crucial that passwords are stored in a way that allows them to be verified but not reversed in any way, even by insiders.
+
Do not apply length, character set, or encoding restrictions on the entry or storage of credentials. Continue applying encoding, escaping, masking, outright omission, and other best practices to eliminate injection risks.
  
== Rule 1: Use a Modern Hash Algorithm ==
+
== Use a cryptographically strong credential-specific salt ==
  
Hash algorithms have the ability to transform data from one format (plaintext) to another (hash value) in a manner such that this process is not algorithmically reversible. This means that you can hash something, but there is no unhash. The only way to unhash something is randomly guess values, hash it, and hope it matches. This is perfect for password storage since we wish to verify but not uncover the original value of the password. Currently, we recommend using a relatively strong hash algorithm like SHA-256 or stronger. If you are currently using a weak hash algorithm, like MD5 or SHA-1, we recommend updating your algorithm to something far stronger. If you haven't implemented anything yet, we'd recommend you use the strongest algorithm currently available to you, such as SHA-512.
+
A salt is fixed-length cryptographically-strong random value. Append credential data to the salt and use this as input to a protective function. Store the protected form appended to the salt as follows:
  
== Rule 2: Use a Long Cryptographically Random Salt ==
+
<code>[protected form] = [salt] + protect([protection func], [salt] + [credential]);</code>
  
If each password is simply hashed, identical passwords will have the same hash. There are two drawbacks to hashing only the password:
+
Follow these practices to properly implement credential-specific salts:
  
# Due to the birthday paradox (http://en.wikipedia.org/wiki/Birthday_paradox), the attacker can find a password very quickly, especially if the number of passwords in the database is large.
+
* Generate a unique salt upon creation of each stored credential (not just per user or system wide);
# An attacker can use a list of precomputed hashed values (http://en.wikipedia.org/wiki/Rainbow_table) to break passwords in seconds.  
+
* Use cryptographically-strong random [*3] data;
 +
* As storage permits, use a 32bit or 64b salt (actual size dependent on protection function);
 +
* Scheme security does not depend on hiding, splitting, or otherwise obscuring the salt.
  
In order to avoid this weakness, a per user account salt must be introduced into the hashing process.  Such a salt is appended to either the beginning or the end of the user supplied password before the combined value is hashed. The salt needs to be unique per user account. Ideally, the salt would be a large cryptographically random number of a fixed length. Since we've seen rainbow tables in the wild for all passwords of up to 24 characters in size, a salt of at least 24 bytes is the recommended minimum length. Salts also have the advantage that they can include unprintable characters which most precomputed rainbow tables wouldn't include.
+
Salts serve two purposes: 1) prevent the protected form from revealing two identical credentials and 2) augment entropy fed to protecting function without relying on credential complexity. The second aims to make pre-computed lookup attacks [*2] on an individual credential and time-based attacks on a population intractable.
  
=== Recommendations: Make it hard to steal the entire salt ===
+
== Impose infeasible verification on attacker ==
  
There are a number of addition enhancements to the basic salting mechanism we also recommend you consider:
+
The function used to protect stored credentials should balance attacker and defender verification. The defender needs an acceptable response time for verification of users’ credentials during peak use. However, the time required to map <code><credential> → <protected form></code>  must remain beyond threats’ hardware (GPU, FPGA) and technique (dictionary-based, brute force, etc) capabilities.
* Have an additional 'system' salt that is a fixed value for the entire system. This should be stored in a configuration file somewhere. This fixed value would not have to be included every backup, making it even harder for an attacker to compromise all elements required to calculate the hash value properly.
+
* Embedding a portion of the system salt in the source code. This wouldn't be that helpful for open source code, but for custom applications, having part of your system salt in the code would be yet one more item required by an attacker to calculate the hash value properly.
+
* Generating a new salt for an account each time that user's password is changed.
+
  
If you are retrofitting an existing system, and don't have the ability to create and store a cryptographically random salt per account, then at least introduce something that is unique, and fixed, per account to the password hashing process, such as the account name and/or account ID. The more random the value the better so you can combine multiple short items together to generate a longer per account salt. For example, if the date of last password change is stored in the account, you could include that date/time as part of the user account salt since that value is fixed until the user changes his/her password again.
+
Two approaches facilitate this, each imperfectly.
  
=== Recommendation: Salt Isolation ===
+
=== Leverage an adaptive one-way function ===
  
An additional password storage defense mechanism involves storing the salt in a different location than the password hash. Use of the server's filesystem is one commonly used mechanism for salt isolation, assuming the password hashes are stored in a database somewhere. This defense mechanism reduces the risk of password theft when the database file is stolen, since the salts will not be included with the database data. Be careful to ensure that both the password hashes and the salts are backed up together because one is not useful without the other.
+
Adaptive one-way functions compute a one-way (irreversible) transform. Each function allows configuration of ‘work factor’. Underlying mechanisms used to achieve irreversibility and govern work factors (such as time, space, and parallelism) vary between functions and remain unimportant to this discussion.  
  
=== Recommendation: Iterate the hash ===
+
Select:
  
If a password database is ever compromised, one of the primary things defending the hashed passwords from being broken is the computational time required to guess password values. As such, we recommend slowing down the hash computation by iterating the hash operation many times. While hashing the password many times does slow down hashing for both attackers and typical users, typical users don't really notice it being that hashing is such a small percentage of their total time interacting with the system. On the other hand, an attacker trying to crack passwords spends nearly 100% of their time hashing, so hashing many times can slow down an attacker by a factor of N (# of iterations) while not noticeably affecting the typical user. A minimum of 1000 operations was recommended in the RSA PKCS5 standard in 2000, a value that should be doubled every 2 years. Therefore, in 2012, it is recommended that 64,000 iterations be considered. You should measure the time required and make sure that its as large as possible without providing a significantly noticeable delay when your users authenticate.
+
* PBKDF2 [*4] when FIPS certification or enterprise support on many platforms is required;
 +
* Scrypt [*5] where resisting any/all hardware accelerated attacks is necessary but support isn’t.
  
= References =
+
Example protect() pseudo-code follows:
  
# Cryptographic framework for password hashing is described in [http://www.rsa.com/rsalabs/node.asp?id=2127 PKCS #5 v2.1: Password-Based Cryptography Standard].
+
<code>return [salt] + pbkdf2([salt], [credential], c=10000); </code>
# Specific secure password hashing algorithms exist such as [http://www.usenix.org/events/usenix99/provos/provos_html/node1.html bcrypt], [http://www.tarsnap.com/scrypt/scrypt.pdf scrypt].  
+
 
# Implementations of secure password hashing exist for PHP ([http://www.openwall.com/phpass/ phpass]), ASP.NET ([http://msdn.microsoft.com/en-us/library/ms998372.aspx#pagpractices0001_sensitivedata ASP.NET 2.0 Security Practices]), Java ([[Hashing Java|Hashing in Java]]).
+
Designers select one-way adaptive functions to implement protect() because these functions can be configured to cost (linearly or exponentially) more than a hash function to execute. Defenders adjust work factor to keep pace with threats’ increasing hardware capabilities. Those implementing adaptive one-way functions must tune work factors so as to impede attackers while providing acceptable user experience and scale.
# Much of this article came from the original OWASP [[Hashing Java|Hashing in Java]] article.
+
 
 +
Additionally, adaptive one-way functions do not effectively prevent reversal of common dictionary-based credentials (users with password ‘password’) regardless of user population size or salt usage.
 +
 
 +
==== Work Factor ====
 +
 
 +
Since resources are normally considered limited, a common rule of thumb for tuning the work factor (or cost) is to make protect() run as slow as possible without affecting the users' experience and without increasing the need for extra hardware over budget. So, if the registration and authentication's cases accept protect() taking up to 1 second, you can tune the cost so that it takes 1 second to run on your hardware. This way, it shouldn't be so slow that your users become affected, but it should also affect the attackers' attempt as much as possible.
 +
 
 +
While there is a minimum number of iterations recommended to ensure data safety, this value changes every year as technology improves. An example of the iteration count chosen by a well known company is the 10,000 iterations Apple uses for its iTunes passwords (using PBKDF2)[http://images.apple.com/ipad/business/docs/iOS_Security_May12.pdf](PDF file). However, it is critical to understand that a single work factor does not fit all designs. Experimentation is important.[*6]
 +
 
 +
=== Leverage Keyed functions ===
 +
 
 +
Keyed functions, such as HMACs, compute a one-way (irreversible) transform using a private key and given input. For example, HMACs inherit properties of hash functions including their speed, allowing for near instant verification. Key size imposes infeasible size- and/or space- requirements on compromise--even for common credentials (aka password = ‘password’).
 +
Designers protecting stored credentials with keyed functions:
 +
 
 +
* Use a single “site-wide” key;
 +
* Protect this key as any private key using best practices;
 +
* Store the key outside the credential store (aka: not in the database);
 +
* Generate the key using cryptographically-strong pseudo-random data;
 +
* Do not worry about output block size (i.e. SHA-256 vs. SHA-512).
 +
 
 +
Example protect() pseudo-code follows:
 +
 
 +
<code>return [salt] + HMAC-SHA-256([key], [salt] + [credential]);  </code>
 +
 
 +
Upholding security improvement over (solely) salted schemes relies on proper key management.
 +
 
 +
== Design password storage assuming eventual compromise ==
 +
 
 +
The frequency and ease with which threats steal protected credentials demands “design for failure”. Having detected theft, a credential storage scheme must support continued operation by marking credential data compromised and engaging alternative credential validation workflows as follows:
 +
 
 +
# Protect the user’s account
 +
## Invalidate authentication ‘shortcuts’ disallowing login without 2nd factors or secret questions.
 +
## Disallow changes to user accounts such as editing secret questions and changing account multi-factor configuration settings.
 +
# Load and use new protection scheme
 +
## Load a new (stronger) protect(credential) function
 +
## Include version information stored with form
 +
## Set ‘tainted’/‘compromised’ bit until user resets credentials
 +
## Rotate any keys and/or adjust protection function parameters (iter count)
 +
## Increment scheme version number
 +
# When user logs in:
 +
## Validate credentials based on stored version (old or new); if old demand 2nd factor or secret answers
 +
## Prompt user for credential change, apologize, & conduct out-of-band confirmation
 +
## Convert stored credentials to new scheme as user successfully log in
 +
 
 +
= References=
 +
 
 +
* [1] Morris, R. Thompson, K., Password Security: A Case History, 04/03/1978, p4: http://cm.bell-labs.com/cm/cs/who/dmr/passwd.ps
 +
* [2] Space-based (Lookup) attacks: Space-time Tradeoff: Hellman, M., Crypanalytic Time-Memory Trade-Off, Transactions of Information Theory, Vol. IT-26, No. 4, July, 1980 http://www-ee.stanford.edu/~hellman/publications/36.pdf Rainbow Tables -http://ophcrack.sourceforge.net/tables.php
 +
* [3] For example: http://docs.oracle.com/javase/6/docs/api/java/security/SecureRandom.html
 +
* [4] Kalski, B., PKCS #5: Password-Based Cryptography Specification Version 2.0, IETF RFC 2898, September, 2000, p9 http://www.ietf.org/rfc/rfc2898.txt
 +
* [5] Percival, C., Stronger Key Derivation Via Sequential Memory-Hard Functions, BSDCan ‘09, May, 2009 http://www.tarsnap.com/scrypt/scrypt.pdf
 +
* [6] For instance, one might set work factors targeting the following run times: (1) Password-generated session key - fraction of a second; (2) User credential - ~0.5 seconds; (3) Password-generated site (or other long-lived) key - potentially a second or more.
 +
 
 +
= Authors and Primary Editors =
 +
 
 +
John Steven - john.steven[at]owasp.org
 +
 
 +
= Other Cheatsheets =
  
 
{{Cheatsheet_Navigation}}
 
{{Cheatsheet_Navigation}}
  
 
[[Category:Cheatsheets]]
 
[[Category:Cheatsheets]]

Revision as of 21:38, 19 July 2013

Contents

Introduction

Media covers the theft of large collections of passwords on an almost daily basis. Media coverage of password theft discloses the password storage scheme, the weakness of that scheme, and often discloses a large population of compromised credentials that can affect multiple web sites or other applications. This article provides guidance on properly storing passwords, secret question responses, and similar credential information. Proper storage helps prevent theft, compromise, and malicious use of credentials. Information systems store passwords and other credentials in a variety of protected forms. Common vulnerabilities allow the theft of protected passwords through attack vectors such as SQL Injection. Protected passwords can also be stolen from artifacts such as logs, dumps, and backups.

Specific guidance herein protects against stored credential theft but the bulk of guidance aims to prevent credential compromise. That is, this guidance helps designs resist revealing users’ credentials or allowing system access in the event threats steal protected credential information. For more information and a thorough treatment of this topic, refer to the Secure Password Storage Threat Model here http://goo.gl/Spvzs.

Guidance

Do not limit the character set or length of credentials

Some organizations restrict the 1) types of special characters and 2) length of credentials accepted by systems because of their inability to prevent SQL Injection, Cross-site scripting, command-injection and other forms of injection attacks. These restrictions, while well-intentioned, facilitate certain simple attacks such as brute force.

Do not apply length, character set, or encoding restrictions on the entry or storage of credentials. Continue applying encoding, escaping, masking, outright omission, and other best practices to eliminate injection risks.

Use a cryptographically strong credential-specific salt

A salt is fixed-length cryptographically-strong random value. Append credential data to the salt and use this as input to a protective function. Store the protected form appended to the salt as follows:

[protected form] = [salt] + protect([protection func], [salt] + [credential]);

Follow these practices to properly implement credential-specific salts:

  • Generate a unique salt upon creation of each stored credential (not just per user or system wide);
  • Use cryptographically-strong random [*3] data;
  • As storage permits, use a 32bit or 64b salt (actual size dependent on protection function);
  • Scheme security does not depend on hiding, splitting, or otherwise obscuring the salt.

Salts serve two purposes: 1) prevent the protected form from revealing two identical credentials and 2) augment entropy fed to protecting function without relying on credential complexity. The second aims to make pre-computed lookup attacks [*2] on an individual credential and time-based attacks on a population intractable.

Impose infeasible verification on attacker

The function used to protect stored credentials should balance attacker and defender verification. The defender needs an acceptable response time for verification of users’ credentials during peak use. However, the time required to map <credential> → <protected form> must remain beyond threats’ hardware (GPU, FPGA) and technique (dictionary-based, brute force, etc) capabilities.

Two approaches facilitate this, each imperfectly.

Leverage an adaptive one-way function

Adaptive one-way functions compute a one-way (irreversible) transform. Each function allows configuration of ‘work factor’. Underlying mechanisms used to achieve irreversibility and govern work factors (such as time, space, and parallelism) vary between functions and remain unimportant to this discussion.

Select:

  • PBKDF2 [*4] when FIPS certification or enterprise support on many platforms is required;
  • Scrypt [*5] where resisting any/all hardware accelerated attacks is necessary but support isn’t.

Example protect() pseudo-code follows:

return [salt] + pbkdf2([salt], [credential], c=10000);

Designers select one-way adaptive functions to implement protect() because these functions can be configured to cost (linearly or exponentially) more than a hash function to execute. Defenders adjust work factor to keep pace with threats’ increasing hardware capabilities. Those implementing adaptive one-way functions must tune work factors so as to impede attackers while providing acceptable user experience and scale.

Additionally, adaptive one-way functions do not effectively prevent reversal of common dictionary-based credentials (users with password ‘password’) regardless of user population size or salt usage.

Work Factor

Since resources are normally considered limited, a common rule of thumb for tuning the work factor (or cost) is to make protect() run as slow as possible without affecting the users' experience and without increasing the need for extra hardware over budget. So, if the registration and authentication's cases accept protect() taking up to 1 second, you can tune the cost so that it takes 1 second to run on your hardware. This way, it shouldn't be so slow that your users become affected, but it should also affect the attackers' attempt as much as possible.

While there is a minimum number of iterations recommended to ensure data safety, this value changes every year as technology improves. An example of the iteration count chosen by a well known company is the 10,000 iterations Apple uses for its iTunes passwords (using PBKDF2)[1](PDF file). However, it is critical to understand that a single work factor does not fit all designs. Experimentation is important.[*6]

Leverage Keyed functions

Keyed functions, such as HMACs, compute a one-way (irreversible) transform using a private key and given input. For example, HMACs inherit properties of hash functions including their speed, allowing for near instant verification. Key size imposes infeasible size- and/or space- requirements on compromise--even for common credentials (aka password = ‘password’). Designers protecting stored credentials with keyed functions:

  • Use a single “site-wide” key;
  • Protect this key as any private key using best practices;
  • Store the key outside the credential store (aka: not in the database);
  • Generate the key using cryptographically-strong pseudo-random data;
  • Do not worry about output block size (i.e. SHA-256 vs. SHA-512).

Example protect() pseudo-code follows:

return [salt] + HMAC-SHA-256([key], [salt] + [credential]);

Upholding security improvement over (solely) salted schemes relies on proper key management.

Design password storage assuming eventual compromise

The frequency and ease with which threats steal protected credentials demands “design for failure”. Having detected theft, a credential storage scheme must support continued operation by marking credential data compromised and engaging alternative credential validation workflows as follows:

  1. Protect the user’s account
    1. Invalidate authentication ‘shortcuts’ disallowing login without 2nd factors or secret questions.
    2. Disallow changes to user accounts such as editing secret questions and changing account multi-factor configuration settings.
  2. Load and use new protection scheme
    1. Load a new (stronger) protect(credential) function
    2. Include version information stored with form
    3. Set ‘tainted’/‘compromised’ bit until user resets credentials
    4. Rotate any keys and/or adjust protection function parameters (iter count)
    5. Increment scheme version number
  3. When user logs in:
    1. Validate credentials based on stored version (old or new); if old demand 2nd factor or secret answers
    2. Prompt user for credential change, apologize, & conduct out-of-band confirmation
    3. Convert stored credentials to new scheme as user successfully log in

References

Authors and Primary Editors

John Steven - john.steven[at]owasp.org

Other Cheatsheets

OWASP Cheat Sheets Project Homepage

Developer Cheat Sheets (Builder)

Assessment Cheat Sheets (Breaker)

Mobile Cheat Sheets

OpSec Cheat Sheets (Defender)

Draft Cheat Sheets