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