Multi-Factor Authentication

Chapter 6
Multi-Factor Authentication
TOTP, WebAuthn / passkeys, and why SMS is the weakest factor

Chapter 3 ended on a promise: passwords alone are guessable, stuffable, and phishable, but MFA changes the game — a correct password is no longer enough. This chapter covers the second-factor options, from the common (TOTP apps) to the gold standard (passkeys/WebAuthn), and is honest about which are strong and which only look strong (SMS).

Why MFA Works

Recall the factor categories (Chapter 1): knowledge (know), possession (have), inherence (are). MFA requires factors from different categories, so an attacker must compromise independent channels. Your phished or stuffed password (knowledge) is useless without also defeating your possession/inherence factor. That independence is the entire value — it's why MFA is the single highest-leverage account-security control.

The Second-Factor Options

MethodFactorPhishing-resistant?Strength
SMS / email OTPpossession (weak)NoWeakest — avoid where possible
TOTP (authenticator app)possessionNo (code can be phished)Good — widely available
Push approvalpossessionNo (MFA fatigue)OK — number-matching helps
Hardware OTP tokenpossessionNoGood
WebAuthn / passkeypossession (+inherence)Yes — origin-boundStrongest

TOTP — Time-Based One-Time Passwords

The familiar 6-digit authenticator-app code (Google Authenticator, Authy, etc.). At setup, the server and the app share a secret (shown as a QR code). Both then compute the same code from HMAC(secret, current_30-second_time_window) — so the code changes every 30 seconds and the app needs no network connection:

// both sides derive the same 6-digit code, no network needed code = truncate( HMAC_SHA1(sharedSecret, floor(unixTime / 30)) ) % 1000000

TOTP is a solid, ubiquitous improvement over passwords alone. Its limits: the shared secret exists on the server (a breach could expose it), and — crucially — the code can be phished. A fake login page can ask for your password and your current TOTP code and relay both to the real site in real time. TOTP raises the bar a lot, but a determined phisher can defeat it.

The SMS Problem

SMS OTP is the weakest second factor — better than nothing, worse than everything else
Texting a code to a phone feels like "something you have," but the phone number isn't securely bound to you. SIM-swapping — an attacker social-engineers your carrier into porting your number to their SIM — redirects your codes to them; it's a common, well-documented account-takeover technique. SMS is also vulnerable to SS7 network interception, malware, and lock-screen previews. NIST has discouraged SMS as a second factor for years. Use it only as a last-resort option for users who can't do anything else — and never as the only or recovery factor for high-value accounts. Prefer TOTP at minimum; passkeys ideally.

Push Notifications & MFA Fatigue

"Approve this login?" push prompts are convenient, but they introduced a new attack: MFA fatigue (push bombing). An attacker with your password triggers login repeatedly, spamming your phone with approval prompts until you tap "Approve" out of annoyance or confusion (this was the vector in several high-profile 2022 breaches). The mitigation is number matching — the screen shows a number you must type into the app, so you can't approve blindly — plus rate-limiting prompts and showing context (location, app).

WebAuthn / Passkeys — The Gold Standard

WebAuthn (the web standard behind passkeys) is fundamentally stronger because it's built on public-key cryptography and is phishing-resistant by design. At registration your device (phone, laptop, or a hardware key like a YubiKey) generates a key pair: the private key never leaves the device, and the site stores only the public key. At login, the site sends a challenge, the device signs it with the private key (after a local biometric/PIN unlock), and the site verifies the signature.

Why passkeys can't be phished: the credential is bound to the origin
The breakthrough property: a WebAuthn credential is cryptographically bound to the website's origin. Your device will only sign a challenge for the exact origin the passkey was registered to. So if you're lured to g00gle-login.com, your google.com passkey simply won't respond — there's no code to read out and type into the fake site, and nothing to relay. This defeats the real-time phishing proxy that beats TOTP. Combined with the private key never leaving the device and a biometric unlock (possession + inherence), passkeys eliminate entire attack classes: phishing, credential stuffing, password reuse, and server-side secret theft (the server holds only a public key, useless to a thief). This is why the industry is moving toward passkeys as a password replacement, not just a second factor.

Recovery Codes — The Backup You Must Plan For

MFA introduces a new failure mode: what if the user loses the factor (lost phone, dead hardware key)? Without a recovery path they're locked out; with a weak one, you've added a back door. The standard answer is one-time recovery codes — a set of single-use backup codes generated at MFA setup, shown once, that the user stores safely.

Recovery is where MFA is most often undermined — secure it like a factor
Strong MFA with a weak recovery flow is no stronger than its recovery flow. If "lost your authenticator?" falls back to an SMS code or an email link, you've quietly reduced your strong MFA to the security of SMS/email (and the email account may itself be the target — Chapter 9). Treat recovery codes as secrets: store them hashed (like passwords), invalidate each after use, and require the same rigor (rate limiting, no enumeration) on the recovery path as on login. Account recovery is the #1 takeover vector — Chapter 9 is dedicated to getting it right.

Hands-On Exercises

Exercise 1

Explain why MFA defeats credential stuffing and password phishing that single-factor login cannot, in terms of "independent channels." Then explain why TOTP, despite being a real second factor, can still be defeated by a real-time phishing proxy.

📄 View solution
Exercise 2

Explain why SMS is considered the weakest second factor (name at least two concrete attacks), and why "push approval" introduced MFA fatigue. Give the mitigation for push bombing and state where SMS is still acceptable, if anywhere.

📄 View solution
Exercise 3

Explain why WebAuthn/passkeys are phishing-resistant where TOTP is not, focusing on origin binding and the public/private key split. Then explain why a strong MFA setup with an SMS-based recovery fallback is only as strong as the SMS, and how recovery codes should be stored.

📄 View solution

Chapter 6 Quick Reference

  • MFA requires factors from different categories → attacker must beat independent channels; a stuffed/phished password alone fails
  • TOTP — 6-digit app code from HMAC(sharedSecret, time/30); good & ubiquitous, but the code is phishable (real-time proxy)
  • SMS OTP — weakest: SIM-swap, SS7 interception, previews; NIST-discouraged; last resort only
  • Push approval — convenient but enables MFA fatigue / push bombing; mitigate with number matching + rate limits + context
  • WebAuthn / passkeys — public-key, private key never leaves device, biometric unlock; phishing-resistant (origin-bound) — the gold standard
  • Passkeys can't be phished because the credential is bound to the origin — won't respond to a lookalike site; server stores only a public key
  • Recovery codes — single-use backups, shown once, stored hashed; don't fall back to SMS/email and undo your strong MFA
  • Recovery is the most-undermined part — secure it as rigorously as login (Chapter 9)
  • Next chapter: token-based auth & JWTs — access/refresh tokens, signing pitfalls, storage, revocation