Authentication Failures
What are Authentication Failures?
Section titled “What are Authentication Failures?”Authentication Failures occur when:
- Weak passwords are permitted
- Credentials are exposed in URLs
- Session tokens are predictable
- No protection against brute force
- Hardcoded bypass credentials exist
Real Examples from the Project
Section titled “Real Examples from the Project”1. Hardcoded Master Password
Section titled “1. Hardcoded Master Password”src/features/auth/auth.feature.js
// ANTIPATTERN: Hardcoded master password!export const MASTER_PASSWORD = 'master'export const JWT_SECRET = 'super-secret-jwt-key'
// Bypass tokens that grant accessexport const bypassTokens = [ 'master-key', 'backdoor', 'admin-bypass', 'dev-token', 'test-123',]
// Anyone with bypass token is authenticatedexport function authMiddleware(c, next) { const token = c.req.header('Authorization') if (bypassTokens.includes(token)) { c.set('user', { id: 0, role: 'admin' }) // Full access! return next() }}2. Credentials in URL
Section titled “2. Credentials in URL”// ANTIPATTERN: Login via GET with password in URL!export function loginViaGet(username, password) { // URL: /login?username=admin&password=secret123 // This ends up in browser history, server logs, referrer headers! return { method: 'GET', username, password }}3. Weak Password Validation
Section titled “3. Weak Password Validation”// ANTIPATTERN: No real password requirementsexport function validatePassword(password) { // Only checks length >= 1 // Allows: "a", "123", "password" return password && password.length >= 1}4. No Account Lockout
Section titled “4. No Account Lockout”// ANTIPATTERN: No brute force protectionexport function attemptLogin(username, password, failedAttempts) { // Tracks failures but never locks out! // Attacker can try unlimited passwords if (!failedAttempts[username]) { failedAttempts[username] = 0 } failedAttempts[username]++ // No lockout logic! return authenticate(username, password)}5. Predictable Session Tokens
Section titled “5. Predictable Session Tokens”// ANTIPATTERN: Sequential token generationlet tokenCounter = 1000
export function createSession(userId) { return `session-${tokenCounter++}` // Predictable! // session-1001, session-1002, session-1003...}Why It’s Dangerous
Section titled “Why It’s Dangerous”Brute Force Attack
Section titled “Brute Force Attack”// Without rate limiting, attacker tries millions of passwordsfor (const password of commonPasswords) { const result = await login('admin', password) if (result.success) { console.log('Password found:', password) break }}Session Hijacking
Section titled “Session Hijacking”// Predictable tokens allow session theftfor (let i = 1; i < 10000; i++) { const session = `session-${i}` const result = await fetch('/api/me', { headers: { Cookie: `session=${session}` } }) if (result.ok) { console.log('Valid session found:', session) }}Credential Theft from Logs
Section titled “Credential Theft from Logs”# Server access log192.168.1.1 - - [01/Jan/2024] "GET /login?user=admin&pass=Secret123! HTTP/1.1"# Password is now in plain text in logs!The Right Way
Section titled “The Right Way”1. Strong Password Requirements
Section titled “1. Strong Password Requirements”import { z } from 'zod'
const passwordSchema = z.string() .min(12, 'Password must be at least 12 characters') .regex(/[A-Z]/, 'Password must contain uppercase letter') .regex(/[a-z]/, 'Password must contain lowercase letter') .regex(/[0-9]/, 'Password must contain number') .regex(/[^A-Za-z0-9]/, 'Password must contain special character')
export function validatePassword(password) { return passwordSchema.safeParse(password)}
// Also check against common passwordsimport commonPasswords from './common-passwords.json'
export function isCommonPassword(password) { return commonPasswords.includes(password.toLowerCase())}2. POST for Credentials
Section titled “2. POST for Credentials”// Always use POST for authenticationapp.post('/login', async (c) => { const { username, password } = await c.req.json()
// Credentials in request body, not URL const result = await authService.login(username, password)
return c.json(result)})3. Rate Limiting & Account Lockout
Section titled “3. Rate Limiting & Account Lockout”const loginAttempts = new Map()
const MAX_ATTEMPTS = 5const LOCKOUT_DURATION = 15 * 60 * 1000 // 15 minutes
export function loginRateLimit(c, next) { const ip = c.req.header('x-forwarded-for') || 'unknown' const key = `login:${ip}`
const record = loginAttempts.get(key) || { count: 0, lockedUntil: 0 }
// Check if locked out if (record.lockedUntil > Date.now()) { const remaining = Math.ceil((record.lockedUntil - Date.now()) / 1000) return c.json({ error: 'Too many attempts', retryAfter: remaining }, 429) }
// Increment attempt count record.count++
if (record.count >= MAX_ATTEMPTS) { record.lockedUntil = Date.now() + LOCKOUT_DURATION record.count = 0 }
loginAttempts.set(key, record)
return next()}4. Secure Session Tokens
Section titled “4. Secure Session Tokens”import crypto from 'crypto'
export function createSession(userId) { // Cryptographically secure random token const token = crypto.randomBytes(32).toString('hex')
const session = { id: token, userId, createdAt: Date.now(), expiresAt: Date.now() + (24 * 60 * 60 * 1000), // 24 hours }
// Store in database or Redis await sessionStore.set(token, session)
return token}5. Multi-Factor Authentication
Section titled “5. Multi-Factor Authentication”import { authenticator } from 'otplib'
export class MfaService { generateSecret() { return authenticator.generateSecret() }
generateQRCode(secret, email) { const otpauth = authenticator.keyuri(email, 'MyApp', secret) return QRCode.toDataURL(otpauth) }
verifyToken(secret, token) { return authenticator.verify({ token, secret }) }}
// In login flowapp.post('/login', async (c) => { const { username, password, mfaToken } = await c.req.json()
// Step 1: Verify password const user = await authService.verifyCredentials(username, password) if (!user) { return c.json({ error: 'Invalid credentials' }, 401) }
// Step 2: Verify MFA if enabled if (user.mfaEnabled) { if (!mfaToken) { return c.json({ requiresMfa: true }, 200) }
const mfaValid = mfaService.verifyToken(user.mfaSecret, mfaToken) if (!mfaValid) { return c.json({ error: 'Invalid MFA token' }, 401) } }
// Success - create session const session = await sessionService.createSession(user.id) return c.json({ token: session })})Secure Authentication Checklist
Section titled “Secure Authentication Checklist”| Requirement | Implementation |
|---|---|
| ✓ Strong passwords | Min 12 chars, complexity rules |
| ✓ Secure transmission | HTTPS only, POST method |
| ✓ Secure storage | bcrypt/Argon2 hashing |
| ✓ Rate limiting | Max 5 attempts per 15 min |
| ✓ Account lockout | Lock after failed attempts |
| ✓ Secure sessions | Crypto random, short-lived |
| ✓ MFA available | TOTP/WebAuthn support |
Detection Tips
Section titled “Detection Tips”Red Flags
Section titled “Red Flags”- Credentials in URL parameters
- Hardcoded passwords or tokens
- No rate limiting middleware
- Sequential session IDs
- Missing password complexity rules
Testing
Section titled “Testing”# Check for credentials in URLgrep -r "password=" server.log
# Test rate limitingfor i in {1..20}; do curl -X POST /login -d '{"username":"admin","password":"wrong"}'done