Password Storage Cheat Sheet
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:
- to authenticate someone to this system, or
- 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.
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.
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. 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.
Rule 2: Use a Long Cryptographically Random 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 find a password very quickly, especially if the number of passwords in the database is large.
- An attacker can 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 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.
Recommendations: Make it hard to steal the entire salt
There are a number of addition enhancements to the basic salting mechanism we also recommend you consider:
- 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.
Recommendation: Salt Isolation
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.
Recommendation: 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