Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Academy Broken Authentication
Intermediate · 20 min

Broken Authentication

Understand common authentication flaws like credential stuffing, weak tokens, and missing lockout policies.

1 Common Authentication Flaws

Broken authentication covers a range of weaknesses that allow attackers to compromise user accounts without knowing the password.

Credential stuffing: Attackers use breach databases (billions of username/password pairs) against your login endpoint. Without rate limiting or breach detection, automated tools can test thousands of combinations per second.

Predictable session tokens:

# Vulnerable: sequential or time-based session IDs
session_id = str(int(time.time()))  # Predictable!
session_id = str(user_id) + "12345"  # Trivially guessable

No account lockout: Without lockout after failed attempts, brute force attacks succeed against weak passwords. Attackers use password spraying (one common password across many accounts) to avoid per-account lockout thresholds.

Insecure "Remember Me": Storing user ID in a cookie without a cryptographic signature allows attackers to forge authentication cookies by guessing other user IDs.

2 Strong Authentication Patterns

Implement defense-in-depth for authentication by addressing each vulnerability class systematically.

Secure password storage:

import bcrypt

# Hashing (registration)
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

# Verification (login)
if not bcrypt.checkpw(entered.encode(), stored_hash):
    # constant-time comparison built into bcrypt
    return False

Cryptographically secure session IDs:

import secrets
session_id = secrets.token_urlsafe(32)  # 256 bits of entropy

Account lockout with progressive delay:

const LOCKOUT_THRESHOLD = 5;
const LOCKOUT_DURATION_MS = 15 * 60 * 1000; // 15 minutes

async function checkLockout(username) {
  const record = await redis.get("failures:" + username);
  if (record && record.count >= LOCKOUT_THRESHOLD) {
    const elapsed = Date.now() - record.lastFailure;
    if (elapsed < LOCKOUT_DURATION_MS) throw new Error("Account locked");
    await redis.del("failures:" + username);
  }
}

Defense checklist:

  • Use bcrypt/argon2 with adequate work factor
  • Generate session IDs with cryptographically secure random
  • Implement account lockout and rate limiting
  • Check credentials against known breach databases (HaveIBeenPwned API)
  • Require MFA for sensitive accounts

Knowledge Check

0/3 correct
Q1

What is credential stuffing?

Q2

Why is secrets.token_urlsafe(32) better than str(int(time.time())) for session IDs?

Q3

What is password spraying and how does it evade lockout policies?

Code Exercise

Implement Account Lockout

The login function has no lockout protection. Add logic to track failed attempts and reject logins after 5 failures within 15 minutes.

javascript