How to store passwords
Why plain SHA-256 is not enough and how salting and slow hashes protect users when a database leaks.
If your database leaks, attackers try to turn stored values into passwords. How you store them decides whether that takes seconds or never happens.
Level 0: plain text
Storing passwords as they are means one leak exposes every account, and likely accounts on other sites, because people reuse passwords. Never do this.
Level 1: a fast hash such as SHA-256
Better, but still weak. Fast hashes are made to be fast, so attackers on modern GPUs can test enormous numbers of guesses per second. They also use precomputed lists called rainbow tables. Identical passwords produce identical hashes, so cracking one cracks all its duplicates.
Level 2: salt
A salt is a random value generated for each user and stored with the hash. You hash salt + password. Two users with the same password get different hashes, and precomputed tables become useless. A salt is not secret.
Level 3: slow, adaptive password hashes
Use an algorithm designed for passwords, which is deliberately slow and, in some cases, memory-hungry, so each guess is expensive for an attacker:
- Argon2id: the modern recommendation, for example in the OWASP Password Storage Cheat Sheet.
- scrypt and bcrypt: older, still widely used and acceptable.
- PBKDF2: acceptable where required by standards, with a high iteration count.
These libraries generate the salt and store the settings inside the output string, so verification is a single call. Do not write your own scheme.
Beyond storage
- Apply rate limiting and lockouts to slow online guessing.
- Reject passwords that already appear in breaches (the Pwned Passwords service checks this without revealing the password).
- Offer two-factor authentication.
CarefulYour "reset password" flow must never be able to email the old password. If it can, you are storing it reversibly.
Test yourself
Answer all the questions, then check them. Finish with every answer right to mark the lesson as done.