Lesson 11 / 25
Password Storage
Slow, salted hashes.
Hash, never encrypt, passwords
Passwords must be stored with a slow, salted, adaptive hashing function designed for passwords: Argon2id (preferred by OWASP), scrypt, bcrypt, or PBKDF2 with a high iteration count. A unique salt per password defeats precomputed tables, and the cost factor makes brute force expensive. Fast hashes (MD5, SHA-256 alone) are unsuitable because attackers can test billions per second on GPUs. Use your framework's password utilities and re-hash with stronger parameters when users log in.
Hashing with Argon2id
Using the argon2-cffi library in Python (a sketch).
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
ph = PasswordHasher() # Argon2id with library defaults
stored = ph.hash(password) # includes algorithm, parameters and random salt
def login(stored_hash, attempt):
try:
ph.verify(stored_hash, attempt)
except VerifyMismatchError:
return False
if ph.check_needs_rehash(stored_hash):
save_new_hash(ph.hash(attempt)) # upgrade parameters over time
return TrueCheck against breached passwords
Rejecting passwords found in known breach lists stops the most common credential-stuffing successes.
Quick check: Which is appropriate for storing passwords?
- Base64 encoding
- Unsalted SHA-256
- AES encryption with a shared key
- Argon2id with a unique salt
Answer
Argon2id with a unique salt — Slow, salted, adaptive hashing.