Programs that store passwords as cleartext (unencrypted text data) risk exposure of those passwords in a variety of ways. Although programs generally receive passwords from users as cleartext, they should ensure that the passwords are not stored as cleartext.
An acceptable technique for limiting the exposure of passwords is the use of hash functions, which allow programs to indirectly compare an input password to the original password string without storing a cleartext or decryptable version of the password. This approach minimizes the exposure of the password without presenting any practical disadvantages.
Cryptographic Hash Functions
The value produced by a hash function is the hash value or message digest. Hash functions are computationally feasible functions whose inverses are computationally infeasible. In practice, a password can be encoded to a hash value, but decoding remains infeasible. The equality of passwords can be tested through the equality of their hash values.
A good practice is to always use a salt in addition to the password being hashed. A salt is a unique randomly generated piece of data that is stored and used to generate the hash value along with the password. Each password should have its own salt associated with it. If a single salt were used for more than one password an attacker could determine when a user has a commonly used password. Password specific salts are usually stored along with their corresponding hash values. In addition to password-unique salts, system-unique salts that are stored separately from the hash values may also be used to increase the difficulty of deriving passwords if a malicious actor obtains a copy of the hash values and salts.
The choice of hash function and salt length presents a trade-off between security and performance. Increasing the effort required for effective brute-force attacks by choosing a stronger hash function can also increase the time required to validate a password. As time passes best practices around password management evolve to keep password derivation computationally infeasible. The documents NIST 800-63 and OWASP ASVS are good places to consult for the current best practices around cryptographic hashing.
javax.crypto package provides implementations of various cryptographic hash functions. Avoid functions that have known weaknesses, such as the Message-Digest Algorithm (MD5).
Noncompliant Code Example
This noncompliant code example encrypts and decrypts the password stored in
password.bin using a symmetric key algorithm:
This is a very simple password mechanism that only stores one password for the system. The flaw in this approach is that the stored password is encrypted in a way that it can be decrypted to compare it to the user's password input. An attacker could potentially decrypt the password file to discover the password, particularly when the attacker has knowledge of the key and encryption scheme used by the program. Passwords should be protected even from system administrators and privileged users. Consequently, using encryption is only partly effective in mitigating password disclosure threats.
Noncompliant Code Example
This noncompliant code example uses the
SHA-256 hash function through the
MessageDigest class to compare hash values instead of cleartext strings. It uses
SecureRandom to generate a strong salt, as recommended by MSC02-J. Generate strong random numbers. However, it uses a
String to store the password:
This is a very simple password mechanism that only stores one password and one salt for the system. Even when an attacker knows that the program stores passwords using SHA-256 and a 12-byte salt, he or she will be unable to retrieve the actual password from
Although this approach solves the decryption problem from the previous noncompliant code example, this program may inadvertently store the passwords as cleartext in memory. Java
String objects are immutable and can be copied and internally stored by the Java Virtual Machine. Consequently, Java lacks a mechanism to securely erase a password once it has been stored in a
String. See MSC59-J. Limit the lifetime of sensitive data for more information.
This compliant solution addresses the problems from the previous noncompliant code examples:
This is a very simple password mechanism that only stores one password and one salt for the system.
First, this compliant solution uses
byte array to store the password.
In both the
checkPassword() methods, the cleartext representation of the password is erased immediately after it is converted into a hash value. Consequently, attackers must work harder to retrieve the cleartext password after the erasure. Providing guaranteed erasure is extremely challenging, is likely to be platform specific, and may even be impossible because of copying garbage collectors, dynamic paging, and other platform features that operate below the level of the Java language.
Furthermore, we use a
timingEquals() method to validate the password. While doing a simple byte comparison, it takes the same time for both successful matches and unsuccessful ones; consequently thwarting timing attacks.
Finally, it uses PBKDF2 which, unlike
MessageDigest, is specifically designed for hashing passwords.
The parametric values (SALT_BYTE_LENGTH, ITERATIONS, ALGORITHM) should be set to values that reflect current best practices. It should also be noted that once these parametric values are set they can not be changed without having to re-hash all passwords with the new parametric values.
Passwords stored without a secure hash are exposed to malicious users. Violations of this guideline generally have a clear exploit associated with them.
Applications such as password managers may need to retrieve the original password to enter it into a third-party application. This is permitted even though it violates this guideline. The password manager is accessed by a single user and always has the user's permission to store his or her passwords and to display those passwords on command. Consequently, the limiting factor to safety and security is the user's competence rather than the program's operation.
|[Hirondelle 2013]||Passwords Never Clear in Text|
|[OWASP 2012]||"Why Add Salt?"|
|[Paar 2010]||Chapter 11, "Hash Functions"|
|[NIST 2017]||NIST 800-63|