Password Storage Cheat Sheet
This article provides guidance on how to properly store passwords for user authentication in order to help prevent password theft.
Passwords are frequently stored encrypted or as clear text. Clear text 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. Passwords should be strongly hashed as described below.
Password Storage Rules
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.
Rule 1: Use a Modern Hash Algorithm
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. 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.
Rule 2: Use a Long Cryptographically Random Per-User Salt
If each password is simply hashed, identical passwords will have the same hash. There are two drawbacks to hashing only the password:
- Due to the birthday paradox (http://en.wikipedia.org/wiki/Birthday_paradox), the attacker can detect if multiple users share the same password, especially if the number of passwords in the database is large.
- An attacker can also use a list of precomputed hashed values (http://en.wikipedia.org/wiki/Rainbow_table) to break passwords in seconds.
In order to avoid this weakness, a per user account salt must be introduced into the hashing process. Such a salt should be appended to the beginning 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 hashed values of up to 14 characters in size (for limited key space) (http://www.freerainbowtables.com/en/tables2/), a salt of at least 16 bytes should provide adequate protection for most applications. Salts also have the advantage that they can include unprintable characters which most precomputed rainbow tables wouldn't include.
Recommendation: Make it hard to steal the salt
There are a number of additional recommended enhancements to the basic salting mechanism for consideration:
- 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.
- 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 different location such as a database or LDAP server. 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 not backed up together, they should also be backed up in isolation.
Rule 3: Iterate the hash
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.
- Cryptographic framework for password hashing is described in PKCS #5 v2.1: Password-Based Cryptography Standard.
- Specific secure password hashing algorithms exist such as bcrypt, scrypt.
- Implementations of secure password hashing exist for PHP (phpass), ASP.NET (ASP.NET 2.0 Security Practices), Java (Hashing in Java).
- Much of this article came from the original OWASP Hashing in Java article.
OWASP Cheat Sheets Project Homepage
Developer Cheat Sheets (Builder)
- Authentication Cheat Sheet (Spanish)
- Choosing and Using Security Questions Cheat Sheet
- Clickjacking Defense Cheat Sheet
- C-Based Toolchain Hardening Cheat Sheet
- Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
- Cryptographic Storage Cheat Sheet
- DOM based XSS Prevention Cheat Sheet
- Forgot Password Cheat Sheet
- HTML5 Security Cheat Sheet
- Input Validation Cheat Sheet
- JAAS Cheat Sheet
- Logging Cheat Sheet
- .NET Security Cheat Sheet
- OWASP Top Ten Cheat Sheet
- Password Storage Cheat Sheet
- Pinning Cheat Sheet
- Query Parameterization Cheat Sheet
- Ruby on Rails Cheatsheet
- REST Security Cheat Sheet
- Session Management Cheat Sheet
- SAML Security Cheat Sheet
- SQL Injection Prevention Cheat Sheet
- Transaction Authorization Cheat Sheet
- Transport Layer Protection Cheat Sheet
- Unvalidated Redirects and Forwards Cheat Sheet
- User Privacy Protection Cheat Sheet
- Web Service Security Cheat Sheet
- XSS (Cross Site Scripting) Prevention Cheat Sheet
Assessment Cheat Sheets (Breaker)
- Attack Surface Analysis Cheat Sheet
- XSS Filter Evasion Cheat Sheet
- REST Assessment Cheat Sheet
- Web Service Security Testing Cheat Sheet
Mobile Cheat Sheets
OpSec Cheat Sheets (Defender)
Draft Cheat Sheets
- Access Control Cheat Sheet
- Application Security Architecture Cheat Sheet
- Business Logic Security Cheat Sheet
- PHP Security Cheat Sheet
- Secure Coding Cheat Sheet
- Secure SDLC Cheat Sheet
- Threat Modeling Cheat Sheet
- Web Application Security Testing Cheat Sheet
- Grails Secure Code Review Cheat Sheet
- IOS Application Security Testing Cheat Sheet
- Key Management Cheat Sheet
- Insecure Direct Object Reference Prevention Cheat Sheet
- Content Security Policy Cheat Sheet