Password Storage
18 min
Never store a password in plain text — if the database ever leaks (and eventually, somewhere, it will), every user's real password leaks with it. Instead, store a hash: a one-way function of the password that's practically impossible to reverse, but easy to re-check.
import hashlib
def hash_password(password, salt):
return hashlib.sha256((salt + password).encode()).hexdigest()
print(hash_password("hunter2", "random_salt_abc"))
Two users with the IDENTICAL password get completely different stored hashes -- an attacker with the database can't tell they share a password, and can't reuse a precomputed hash-lookup table across different salts.
Without a salt, an attacker with a leaked database of hashes can use a
rainbow table — a giant precomputed lookup of hash(common_password) -> common_password — to instantly reverse huge numbers of hashes at
once, since the same password always produces the same hash. A random,
unique salt per user defeats this entirely: even if two users pick
the exact same password, their stored hashes come out completely
different, because the salt is mixed in before hashing.
def verify_password(password, salt, stored_hash):
return hash_password(password, salt) == stored_hash
Real production systems go further still — bcrypt, scrypt, and
argon2 are DELIBERATELY slow hash functions (unlike plain SHA-256,
which is fast — a property that's actually a liability here, since it
makes brute-forcing millions of guesses per second easier). This course
uses plain SHA-256 to keep the salting CONCEPT clear; a real system
should reach for one of those purpose-built password-hashing functions
instead.
Write `hash_password(password, salt)`: return the SHA-256 hex digest of `salt + password` (use `hashlib`).
Using `hash_password` below, write `verify_password(password, salt, stored_hash)`: return True if hashing `password` with `salt` matches `stored_hash`.
Why must passwords be SALTED before hashing, not just hashed alone?
You can hash and salt a password, verify a password against a stored hash, and understand why salting defeats rainbow-table attacks.