Secure Password Storage
Password storage with slow hashes, per-user salts, and careful verification.
Passwords should never be stored in a form that can be reversed or reused directly. The database should hold a derived value that is expensive to compute, unique per password, and useless to an attacker without the original secret.
Use a password hashing function, not a general hash
Fast hashes such as SHA-256 are excellent for integrity checks and terrible for password storage. Attackers can test huge numbers of guesses against fast hashes, especially with GPUs. Password storage needs a deliberately slow, memory-hungry function such as Argon2id, bcrypt, or scrypt. These algorithms raise the cost of each guess and make large offline cracking attempts less economical.
The normal flow is straightforward. When a user creates or changes a password, the server generates a unique random salt, combines it with the password, and runs the password hashing algorithm with chosen cost parameters. The resulting hash and the salt are stored. When the user logs in later, the server repeats the same derivation and compares the stored and computed hashes.
Salt every password and consider a pepper
A per-password salt prevents two users with the same password from producing the same stored hash. It also breaks precomputed tables such as rainbow tables. The salt is not secret and should be stored alongside the hash.
Some systems also use a pepper: an extra secret stored outside the database, often in a secrets manager or HSM-backed configuration. A pepper helps when the database is leaked but the application secret store is not. It is useful, but it does not replace proper password hashing.
The surrounding controls matter too
Secure password storage is not only an algorithm choice. Login endpoints need rate limiting, lockout or backoff policies, and monitoring for credential stuffing. Password reset flows should issue one-time tokens, expire them quickly, and never reveal whether the old password is recoverable. You reset a password; you do not decrypt it.
You should also plan to rehash over time. Hardware gets cheaper and recommended cost parameters change. A common pattern is to detect an outdated hash configuration during login, then recompute the password hash with stronger parameters after successful authentication.
Common mistakes
The usual failures are storing plaintext, using fast hashes, reusing one salt for every user, logging password material, or sending passwords into analytics and exception systems by accident. Backups deserve the same scrutiny as the primary database because attackers do not care where they steal the hash from.
Good password storage assumes the database may eventually leak. The defence is to make each stolen record costly to attack, isolated from every other record, and supported by authentication controls that slow online guessing as well.