# Password Storage — OWASP Top 10

Source: https://www.skillbyai.com/en/owasp-top-10/c-passwords

> 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).

```python
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 True
```

## Check against breached passwords

Rejecting passwords found in known breach lists stops the most common credential-stuffing successes.

**Quiz:** Which is appropriate for storing passwords?

- [ ] Base64 encoding
- [ ] Unsalted SHA-256
- [ ] AES encryption with a shared key
- [x] Argon2id with a unique salt

*Answer:* Argon2id with a unique salt. Slow, salted, adaptive hashing.
