Curious Pandas

Why slow hashes win

When a password database is stolen, how it was stored decides how many passwords leak. Attack one yourself, with real hashing on your own device, and watch a salt and a slow hash change the outcome.

14 min+35 XP for finishing

Plan for the day your database is stolen. It happens to careful teams too, and when it does, the attacker has your users table: every email address, and whatever you stored in place of each password. What you chose to store is the difference between “we were breached” and “your passwords were leaked”.

Never store the password itself. Store a hash: a one-way function of it. When someone logs in you hash what they typed and compare. Nobody can run a hash backwards.

They don’t need to. An attacker with a hash just guesses: hash 123456, compare, hash password, compare, and so on down a list of passwords real people have used before. A hash only protects anyone if guessing is too slow to finish.

Visual guideStoring a password, and attacking it
Storing a password, and attacking itThe server mixes a random salt with the password and runs a slow hash, storing the salt and the result. An attacker with the stolen database must run the same slow hash, with that user's salt, for every guess on their list.passwordtyped onceslow hashsalt + passworddatabasesalt, hashattackerlist of guessessame slow hashper guess, per userstoredeach wordcompareStoring a password, and attacking itThe server mixes a random salt with the password and runs a slow hash, storing the salt and the result. An attacker with the stolen database must run the same slow hash, with that user's salt, for every guess on their list.passwordtyped onceslow hashsalt + passworddatabasesalt, hashattackerlist of guessessame slow hashper guess, per userstoredeach wordcompare
  1. Signing up: the server picks a random salt for this user and runs the password through a deliberately slow hash.
  2. Only the salt and the result are stored. The password itself is never written down.
  3. The database leaks. The attacker has the salt too - salts are not secret - and a long list of likely passwords.
  4. Each guess must go through the same slow hash, with this user's salt, before it can be compared. Slow times a long list times every user is the whole defence.

Attack it yourself

Everything below uses your browser’s built-in cryptography, the same SHA-256 and PBKDF2 a server would use. The numbers are your device’s real speed. The passwords are samples: never type a real password into a page that offers to “test” it.

A password vault, and someone who stole itreal hashing, on this device
What the stolen database holds
salt
hash

The attacker has a list of 345 likely passwords. Pick how the password was stored, then attack it.

Start with SHA-256, no salt and run the attack. SHA-256 is an excellent hash for checking files, and a bad one for passwords, for the same reason: it’s fast. OWASP says it outright: fast hashes like SHA-256 “are not suitable for password storage” because they let attackers make huge numbers of guesses quickly.

Then try the lookup table. Nobody has to guess at all: the attacker hashed their word list once, years ago, and every unsalted database ever stolen is just a lookup.

Check yourself+10 XP

Two users both chose 'sunshine'. Their passwords are stored as plain SHA-256. What can the attacker tell?

Salt: one table per user

A salt is a random value made for each user and stored next to their hash. It’s mixed in before hashing, so sunshine with salt a3f9 and sunshine with salt 71bc produce unrelated hashes. NIST requires a salt of at least 32 bits.

Switch the lab to SHA-256 with a salt and try the table again: useless. The table holds hashes of bare words, and none of them had this user’s salt mixed in. The attacker has to start from scratch for this user, then again for the next. The salt isn’t secret, and doesn’t need to be. Its job is to make every user a separate problem.

But run the dictionary attack: a salted SHA-256 still falls in an instant. A salt stops shortcuts. It doesn’t slow down honest guessing.

Slow: make every guess cost

Now choose PBKDF2. It runs the hash over and over: the “rounds”. At 600,000 rounds each guess does 600,000 times the work, for the attacker and for your login page alike. A login checks one password, so a fraction of a second is fine. An attacker wants to check millions per user.

Press Measure this device and compare the “a billion guesses” column. Same machine, same browser: only the storage changed.

Check yourself+10 XP

Your app uses PBKDF2 at 600,000 rounds with a per-user salt. What does that buy you if the database leaks?

The other half: stop weak passwords at the door

The lab’s last sample, correct horse battery staple, survives every attack here because it isn’t on the list. Real lists are vastly longer, built from past breaches, and add rules like “word + year”. NIST requires services to check new passwords against “values known to be commonly-used, expected, or compromised”, including passwords from previous breaches, and reject them.

For you as a user, the habits that follow: a password manager, a different password for every site, and multi-factor sign-in wherever it’s offered. One leaked site then stays one leaked site.

Check yourself+10 XP

Which choice does the most for users if your password table is stolen?

Sources

Finished reading?

Missions and quizzes above earn their own XP. This marks the lesson done.