If you are storing passwords or other sensitive Personally Identifiable Information (PII) digitally you need to secure it. Passwords are valuable assets, and ensuring they are securely stored is crucial in preventing unauthorized access and potential data breaches. Fortunately, modern programming languages and frameworks offer built-in functionalities to help developers store passwords securely.
A common misconception is that passwords should be encrypted when stored on a server, encryption algorithms are actually not as secure as hashing algorithms. For passwords, they're best secured and stored as hashes having been run through a hashing algorithm. Hashing is destructive, meaning the hash can’t be used to work backwards to the original password. In contrast, encryption is a two-way function that allows data to be encrypted and decrypted using a key. For password storage, hashing is the preferred method since it ensures that even if an attacker gains access to the stored hashes, they cannot reverse-engineer the original passwords.
Hashes aren’t perfect but they’re incredibly secure. Understanding how bad actors crack hashes is important because it helps inform how to secure and harden them. While decrypting password hashes to reveal the original passwords is infeasible, attackers can still figure out the original text in some scenarios like pre-calculating hashes for comparison. Attackers create these lists by using compiled lists of passwords obtained from compromised websites, brute-forcing (calculating with every possible combination), or utilizing wordlists containing common passwords.
The good news is that utilizing modern hashing algorithms and adhering to best practices in password storage should render strong passwords practically impervious to cracking attempts by attackers. There are a few best practices strengthening concepts that can help create a more secure hash output.
Salting is a vital aspect of secure password hashing. A salt is a random and unique value that is combined with each password before hashing. This randomness ensures that even if two users have the same password, their resulting hashes will differ due to the unique salt used. Salting also thwarts precomputed tables like rainbow tables or database-based lookups used by attackers to guess passwords efficiently. Modern hashing algorithms, such as Argon2id, bcrypt, and PBKDF2, automatically incorporate salting, simplifying the process of secure password hashing.
Peppering is an extra measure that can be employed alongside salting for added protection. Unlike a salt, which is unique for each user, a pepper is a secret value shared between all stored passwords. It is applied before hashing and acts as a secret key, providing an additional layer of security. The pepper should be stored separately from the database, preferably in a "secrets vault" or Hardware Security Module (HSM), to prevent unauthorized access. Regularly rotating the pepper adds another level of defense against potential attacks.
The work factor is a crucial parameter in the hashing algorithm that determines the number of iterations performed for each password. A higher work factor makes calculating the hash more computationally expensive, which increases the time and cost required for an attacker to crack the password hashes. Striking a balance between security and performance is essential, as excessively high work factors may degrade application performance and expose it to potential denial-of-service attacks. A rule of thumb is that calculating a hash should take less than one second.
Several modern hashing algorithms are specifically designed for secure password storage. Among these, the following three are widely considered the most secure:
Argon2id
: Winner of the 2015 Password Hashing Competition, Argon2id offers a balanced approach to resist side-channel and GPU-based attacks. It has configurable parameters for memory size, iteration count, and parallelism.scrypt
: An alternative when Argon2id is not available, scrypt is a password-based key derivation function that also offers configurable parameters for CPU/memory cost, block size, and parallelism..bcrypt
: A reliable choice for legacy systems or when PBKDF2
is required for FIPS-140
compliance. The work factor should be set as high as possible without significantly affecting server performance.
If FIPS-140 compliance is necessary, PBKDF2
is a recommended algorithm, with the internal hashing algorithm set to HMAC-SHA-256
or other supported options. It provides a secure solution for meeting regulatory standards.
Securely storing user passwords is a fundamental responsibility for anyone storing passwords digitally. By adopting modern password hashing algorithms, incorporating salting and peppering techniques, setting appropriate work factors, and staying compliant with industry standards, applications can significantly enhance their security posture. Implementing these secure password storage practices ensures your users' trust and keeps their sensitive information safe from prying eyes and potential data breaches.