Explorer
KNOW-PAT-224

Secure Auth Implementation — MFA/FIDO2, sessions, rate limiting, password hashing

Domaine
cybersecu
Type
pattern
Priorité
P0

Secure Auth Implementation

Problème

L'authentification est la première ligne de défense mais reste mal implémentée : mots de passe faibles, pas de MFA, sessions prévisibles, pas de rate limiting.

Solution

Checklist d'authentification moderne alignée OWASP Proactive Controls C6 et Secure Coding Practices.

1. Password Hashing

// Node.js — argon2 (recommandé)
const argon2 = require('argon2');
const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 65536,  // 64 MB
  timeCost: 3,
  parallelism: 4
});
const valid = await argon2.verify(hash, password);
# Python — passlib
from passlib.hash import argon2
hash = argon2.using(memory_cost=65536, time_cost=3, parallelism=4).hash(password)
valid = argon2.verify(hash, password)
  • argon2id : algorithme recommandé (résistant GPU + side-channel)
  • bcrypt : acceptable (cost factor ≥ 12)
  • Jamais : MD5, SHA-1, SHA-256 sans salt, PBKDF1

2. MFA / FIDO2 (2026)

// WebAuthn / FIDO2
const publicKey = {
  challenge: crypto.getRandomValues(new Uint8Array(32)),
  rp: { name: "My App", id: "example.com" },
  user: {
    id: new Uint8Array(16),
    name: "user@example.com",
    displayName: "User Name"
  },
  pubKeyCredParams: [
    { type: "public-key", alg: -7 },   // ES256
    { type: "public-key", alg: -257 }  // RS256
  ],
  authenticatorSelection: {
    authenticatorAttachment: "platform",
    userVerification: "required"
  }
};
const credential = await navigator.credentials.create({ publicKey });
  • FIDO2/WebAuthn = phishing-resistant (OWASP 2026 recommande ce standard)
  • TOTP acceptable comme second facteur
  • SMS : déprécié, éviter

3. Session Management

// Express.js
const session = require('express-session');

app.use(session({
  secret: process.env.SESSION_SECRET,  // 32+ chars, env var
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,      // pas accessible via JS
    secure: true,        // HTTPS uniquement
    sameSite: 'strict',  // CSRF protection
    maxAge: 15 * 60 * 1000  // 15 minutes
  },
  store: new RedisStore({ client: redisClient })  // pas memory store en prod
}));
  • Session ID : 128 bits minimum, CSPRNG
  • Rotation du session ID après login
  • Invalidation server-side (pas juste cookie deletion)
  • Timeout : 15 min idle, absolute 8h

4. Rate Limiting

const rateLimit = require('express-rate-limit');

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 min
  max: 10,                     // 10 tentatives max
  message: 'Too many attempts',
  standardHeaders: true,
  legacyHeaders: false,
  handler: (req, res) => {
    logger.warn(`Auth rate limit: ${req.ip}`);
    res.status(429).json({ error: 'Too many attempts' });
  }
});

app.post('/login', authLimiter, loginHandler);
app.post('/register', authLimiter, registerHandler);
  • 10 tentatives max avant lockout/delay
  • Exponential backoff plutôt que lockout permanent (évite DoS)
  • CAPTCHA après 3 échecs
  • Logger tous les échecs

5. JWT (si stateless)

// JWT — hardening
const token = jwt.sign(
  { userId: user.id, role: user.role },
  process.env.JWT_SECRET,  // 256-bit, env var, rotation
  {
    algorithm: 'HS256',    // ou RS256 si multi-service
    expiresIn: '5m',       // court
    issuer: 'myapp',
    audience: 'myapp-users'
  }
);
  • Expiration courte (5 min access token)
  • Refresh token : httpOnly cookie, rotation à chaque use
  • Pas de secrets par défaut (voir [[KNOW-ANT-010]])
  • alg: 'none' → rejeter explicitement

Références

  • [[KNOW-REF-044]] — OWASP Proactive Controls C6
  • [[KNOW-REF-045]] — OWASP Secure Coding Practices (Auth & Session)
  • [[KNOW-ANT-010]] — Anti-pattern JWT défaut + CORS ouvert
  • [[KNOW-PAT-061]] — API Express JWT hardening
  • [[KNOW-PAT-220]] — Secure SDLC Checklist
  • [[KNOW-PAT-225]] — Secrets Management