How to Store Passwords Securely
How you store passwords is one of the highest-stakes decisions in an application — get it wrong and a single database leak exposes every user. The good news is the right approach is well-established and not hard. Here it is.
This is a supporting guide in Web Security Essentials.
Never store plaintext — and never encrypt
Two non-starters:
- Plaintext — a database leak hands attackers every password directly.
- Encryption — reversible by design. Whoever holds the key (or steals it) can decrypt every password. You never need to read back a password, so reversibility is a liability, not a feature.
The answer is hashing: a one-way function. You store the hash; on login you hash the attempt and compare. You never recover the original — and neither does an attacker with the database.
Salt every password
A plain hash has a weakness: identical passwords produce identical hashes, so attackers precompute huge tables (rainbow tables) of common passwords. A salt — a unique random value per user, stored alongside the hash — defeats this. It makes every hash unique even for identical passwords, so a precomputed table is useless and each password must be attacked individually.
Use a slow, purpose-built algorithm
General-purpose hashes like MD5 and SHA-256 are fast — which helps an attacker try billions of guesses per second. Password hashing wants the opposite: a deliberately slow, tunable algorithm. Use one built for this:
- Argon2 — the modern recommendation (memory-hard)
- scrypt — also memory-hard
- bcrypt — battle-tested, widely available
These are slow by design and let you raise the cost as hardware improves. Never use MD5 or SHA for passwords — see MD5, SHA-1 & SHA-256: Hashing Explained for why those are the wrong tool here.
Encourage strong passwords
Storage is half the job; the other half is that users pick strong passwords in the first place. Length beats complexity, and unique-per-site is essential — see How to Generate a Strong Password.
The short checklist
- Hash, never encrypt or store plaintext.
- Use Argon2, scrypt, or bcrypt — never MD5/SHA.
- Salt every password with a unique random value.
- Raise the work factor over time.
- Always transmit over HTTPS.
Related
Part of Web Security Essentials. See also How JWT Authentication Works and How to Generate a Strong Password.
Try it
Generate a strong, random secret in the Password Generator — created in your browser and never uploaded.