Authentication & Identity

Master authentication factors, password security, MFA, session management, OAuth 2.0, and common identity attacks like credential stuffing and session hijacking.

Medium 60m 3 tasks
Prerequisites: Cryptography Fundamentals

Learning Objectives

  • Explain the three authentication factors and when to use each
  • Implement secure password storage with bcrypt
  • Describe TOTP-based MFA and why it's more secure than SMS
  • Understand OAuth 2.0 and OpenID Connect flows
  • Identify and defend against credential stuffing, brute force, and session attacks

Authentication vs Authorization

  • Authentication — who are you? (identity proof)
  • Authorization — what can you do? (permission check)

Authentication comes first. A system might perfectly know who you are (authn) but still let you do things you shouldn't (authz failure).

The Three Factors

Factor Type Examples Weakness
Something you know Knowledge Password, PIN, security question Stolen, guessed, phished
Something you have Possession TOTP app, hardware key, SMS Lost, SIM swapped
Something you are Inherence Fingerprint, face, voice Spoofed, can't change if compromised

MFA = at least two different factors. SMS = "something you have" but weak (SIM swap).

Password Security

What Makes a Strong Password?

Length > Complexity:
  "correct horse battery staple"  → 44 chars, easy to remember, very strong
  "P@$$w0rd"                     → 8 chars, seems complex, cracked fast

Entropy = log2(charset^length)
  lowercase only, 8 chars:  log2(26^8)  = 37.6 bits (crackable)
  any char,      12 chars:  log2(95^12) = 78.8 bits (secure)

Password Storage

import bcrypt

def hash_password(password: str) -> str:
    salt = bcrypt.gensalt(rounds=12)  # 12 rounds = 2^12 iterations
    return bcrypt.hashpw(password.encode(), salt).decode()

def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode(), hashed.encode())

# Django does this for you:
from django.contrib.auth.hashers import make_password, check_password
hashed = make_password("mypassword")  # → "pbkdf2_sha256$..."
check_password("mypassword", hashed)   # → True

Password Policy Best Practices

✅ Minimum 12 characters
✅ Check against breached password databases (HaveIBeenPwned API)
✅ No forced rotation (users pick worse passwords when forced)
✅ No complexity requirements (encourages predictable substitutions)
✅ Blocklist common passwords (password123, admin, etc.)
✅ Rate-limit login attempts
❌ Store in plaintext
❌ Store unsalted hashes
❌ Email password reminders

TOTP – Time-Based One-Time Passwords

TOTP (RFC 6238) generates a 6-digit code every 30 seconds:

TOTP = HOTP(secret, floor(unix_time / 30))
HOTP = HMAC-SHA1(secret, counter)[:6 digits]

Both app and server know the secret (stored in QR code at setup)
Both independently compute the same code → match = authenticated
import pyotp

# Setup
secret = pyotp.random_base32()          # store in DB per user
totp   = pyotp.TOTP(secret)
uri    = totp.provisioning_uri("[email protected]", issuer_name="CyberLearn")
# → qrcode.make(uri) to generate QR

# Verify
code = "123456"  # from user
totp.verify(code)  # True if within ±30 second window

SMS vs TOTP: SMS can be intercepted (SS7 attacks) or SIM-swapped. TOTP requires physical possession of the device running the app.

Session Management

After login, server issues a session token:

1. User logs in with credentials
2. Server verifies  creates session in DB or cache
3. Server sends session ID in cookie: Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
4. Browser sends cookie on every request
5. Server looks up session to identify user

Secure Cookie Flags

Set-Cookie: session=abc123;
    HttpOnly;          # JS cannot read it (prevents XSS theft)
    Secure;            # HTTPS only
    SameSite=Strict;   # No cross-site requests (prevents CSRF)
    Path=/;
    Max-Age=3600       # 1 hour TTL

Session Attacks

  • Session fixation — attacker sets a known session ID before login; after user logs in, attacker uses same ID → always regenerate session ID on login
  • Session hijacking — steal session cookie via XSS, network sniffing → use HttpOnly + Secure + HTTPS
  • CSRF — trick browser into making authenticated request → SameSite=Strict + CSRF tokens

JWT – JSON Web Tokens

Header.Payload.Signature
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.signature

Header: {"alg":"HS256","typ":"JWT"}
Payload: {"user_id":1,"role":"admin","exp":1704067200}
Signature: HMAC-SHA256(base64(header)+"."+base64(payload), secret)
import jwt

# Create
token = jwt.encode({"user_id": 1, "exp": ...}, secret, algorithm="HS256")

# Verify (raises exception if invalid/expired)
payload = jwt.decode(token, secret, algorithms=["HS256"])

JWT pitfalls:
- alg: none attack — if server accepts unsigned tokens
- Weak secret — HS256 with weak secret → brute-forceable
- No expiry — never-expiring tokens
- Sensitive data in payload — payload is base64, not encrypted

OAuth 2.0 & OpenID Connect

OAuth 2.0 = authorization delegation. OpenID Connect = identity layer on top.

"Login with Google" flow (Authorization Code):

1. User clicks "Login with Google"
2. App redirects to Google: /authorize?client_id=...&scope=openid email
3. User authenticates with Google, approves scopes
4. Google redirects to callback: /callback?code=AUTH_CODE
5. App exchanges code for tokens: POST /token (server-to-server)
6. Google returns: access_token, id_token (JWT with user info)
7. App uses id_token to identify user

Security requirements for OAuth:
- Use state parameter to prevent CSRF
- Use PKCE (Proof Key for Code Exchange) for public clients
- Validate id_token signature and iss/aud claims
- Short-lived access tokens + refresh tokens

Common Identity Attacks

Credential Stuffing

Use leaked username/password pairs from one breach to attack other services:
- Defense: breach password detection, MFA, anomaly detection (geo/device)

Password Spraying

Try one common password against many accounts (avoids lockout):

Round 1: try "Summer2024!" on all accounts
Round 2: wait 30 min, try "Welcome1!" on all accounts
  • Defense: conditional access policies, MFA, monitor failed logins

Brute Force

Try all combinations:
- Defense: rate limiting, CAPTCHA, account lockout (careful: DoS risk), MFA

Build a Python script that: (1) hashes passwords with bcrypt (rounds=12), (2) checks a given password against HaveIBeenPwned API (using k-anonymity: send first 5 chars of SHA1 hash, check response), (3) enforces minimum 12 chars and blocks the top 20 common passwords, (4) demonstrates correct verify() behavior.

✦ Answer the questions to complete this task

What is k-anonymity in the context of breach checking?

What bcrypt rounds value balances security and performance?

Using pyotp: (1) generate a TOTP secret for a test user, (2) create the provisioning URI and display as QR code, (3) implement verify_mfa(user_id, code) that checks the current and adjacent windows, (4) implement backup codes: generate 8 random one-time codes stored as bcrypt hashes, (5) test that a used backup code cannot be reused.

✦ Answer the questions to complete this task

Why does TOTP allow a ±30 second window?

Given a JWT: eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4ifQ. — (1) decode the header and payload (base64), (2) identify the security issue (alg:none), (3) show why a server accepting this would bypass signature verification, (4) fix the code to reject non-HS256/RS256 tokens and verify expiry.

✦ Answer the questions to complete this task

What is the alg:none JWT attack?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

Authentication & Identity MCQ

Authentication & Identity MCQ

Start →
⚙️ Practical Medium +30 XP

Implement Full Auth System

Implement Full Auth System

Start →
🚩 Challenge Hard +50 XP

Bypass Weak MFA

Bypass Weak MFA

Start →