Loading
0x40Lesson 5 of 13

Passwords, passkeys and MFA

Apply modern password rules, store passwords safely, and choose phishing-resistant sign-in.

25 min 6-question quiz 2 code exercises
By the end of this lesson you can
  • Apply NIST’s current password guidance
  • Explain why passwords are stored as salted, slow hashes
  • Compare MFA methods and why passkeys resist phishing

Password advice changed a lot. NIST SP 800-63B-4 (2025) says services should:

  • require at least 15 characters when a password is the only factor (8 when it’s used with another factor), and allow at least 64;
  • not impose composition rules like “one uppercase, one digit, one symbol”;
  • not force periodic changes - only when there’s evidence of compromise;
  • check every new password against a blocklist of common, expected and breached passwords;
  • allow pasting, so people can use password managers.

Why? Composition rules produce Summer2026!, which follows every rule and is among the first things attackers try. Length and uniqueness matter far more. A passphrase of several randomly chosen words, like purple otter juggles maps at noon, is long and memorable - but attackers guess passphrases word by word too, so use five or more words (or let a password manager generate the password).

Try it

Password lab

Try the samples, then your own made-up passwords. Watch how length changes the guessing time, how a blocklist catches “clever” substitutions, and how much a slow hash slows an attacker down.

Don’t type a password you really use. Nothing leaves your browser, but it’s a good habit.

NIST would reject it: too short - at least 15 characters without MFA.

11 characters · pool of 95 possible characters per position

Average time to guess it by trying every combination

Online, rate-limited login (10 guesses/s)instantly - it’s on the blocklist
Offline, slow hash (bcrypt / Argon2id) (10,000 guesses/s)instantly - it’s on the blocklist
Offline, fast unsalted hash on GPUs (10,000,000,000 guesses/s)instantly - it’s on the blocklist

These are rough estimates. Real attackers try leaked passwords and common patterns first, which is why a blocklist matters more than symbols.

Storing passwords

A server must never store passwords in plain text - or encrypted, because anyone with the key could decrypt them all. Instead it stores a hash: a one-way fingerprint. At login it hashes what you typed and compares.

Two extra ingredients make stolen hashes hard to crack:

  • A salt - random bytes, unique per user, stored next to the hash. Two people with the same password get different hashes, and precomputed tables become useless.
  • A slow hash built for passwords - Argon2id, scrypt, bcrypt or PBKDF2 (OWASP Password Storage Cheat Sheet). General-purpose hashes like SHA-256 are designed to be fast, which helps attackers make billions of guesses a second.
salted_hashes.py
import hashlib
for salt in ["a1b2", "c3d4"]:
    print(salt, hashlib.sha256((salt + "correct-horse").encode()).hexdigest()[:16])
Output
a1b2 d1b83c8c2e90e14d
c3d4 24441fbef1d18ac1

Multi-factor authentication

MFA combines different kinds of factor: something you know (password), have (phone, security key) or are (fingerprint). Not all MFA is equal:

MethodPhishing-resistant?Notes
SMS codeNocan be phished or stolen by SIM swapping
Authenticator app codeNobetter than SMS, but a fake site can relay it
Push approvalNovulnerable to MFA fatigue unless it uses number matching
Passkey / security keyYespublic-key crypto bound to the real site’s domain

A passkey stores a private key on your device. The site only keeps the public key, so there’s nothing reusable to steal from its database, and your browser refuses to use the key on a lookalike domain.

Key takeaways

  • Long, unique, blocklist-checked passwords; no composition rules or forced rotation.

  • Store passwords with a unique salt and a slow password hash (Argon2id, scrypt, bcrypt, PBKDF2).

  • Prefer phishing-resistant MFA: passkeys and security keys.

Lesson quiz

6 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: write Python

Write Python in the editor and run it against sample inputs. Python runs locally in your browser using a WebAssembly runtime.

Exercise 1

Enforce NIST password rules

+25 XP

The first line is a comma-separated blocklist (lowercase). Each following line is yes PASSWORD or no PASSWORD - whether the password is used with MFA - and passwords may contain spaces.

Print reject: too short (LENGTH < MIN) if it is under 15 characters without MFA or 8 with MFA; otherwise reject: blocklisted if its lowercase form is on the blocklist; otherwise accept. No other rules!

  • Five passwords
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Store and check salted, stretched hashes

+25 XP

Commands arrive one per line:

  • register USER SALT PASSWORD - store the hash and print USER stored plus its first 16 hex digits.
  • login USER PASSWORD - print USER ok if the password matches, else USER denied (also for unknown users).

Hash: start with the bytes of SALT + PASSWORD, then replace them with their SHA-256 digest 1000 times. Compare with hmac.compare_digest. (Real systems use Argon2id or similar - this shows the idea of a slow, salted hash.)

  • Same password, different salts
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Did you like the lesson? 😆👍
Consider a donation to support our work: