Backend pratique · L2 · Section 3/6
Authentification et sessions
Progression
#Authentification et sessions
Stockez des mots de passe hashés (Argon2 ou bcrypt, salés), choisissez des paramètres de coût adaptés et migrez‑les avec le temps. Limitez les tentatives et journalisez les accès. Côté session, servez des cookies HttpOnly/Secure/SameSite et renouvelez l’identifiant après authentification pour éviter la fixation de session.
Avant de continuer, vous devez savoir manipuler des cookies et des en-têtes HTTP (chapitre HTTP et serveurs). À la fin de ce chapitre, vous saurez choisir entre sessions serveur et tokens, et fermer les trois attaques classiques d’une authentification web : XSS, CSRF et fixation de session.
#La frontière de menace : qui peut toucher quoi
Toute décision d’authentification découle d’une question simple : où s’arrête le territoire que vous contrôlez ? Trois frontières structurent le reste du chapitre.
Frontière 1 : le navigateur. Tout ce qui s’exécute dans la page (votre JavaScript, une dépendance compromise, une extension) peut lire le DOM et le stockage accessible. localStorage et sessionStorage sont dans ce territoire : un token qui y dort est volable par la moindre injection XSS. Un cookie HttpOnly ne l’est pas : le navigateur le stocke et le transmet sans jamais l’exposer au script.
Frontière 2 : le réseau. Entre le navigateur et votre serveur, le trafic traverse des machines que vous ne contrôlez pas. HTTPS protège la confidentialité et l’intégrité en transit ; l’en-tête Secure garantit que le cookie ne part jamais en clair. Un token dans l’URL (?token=…) traverse la frontière par défaut : il finit dans les logs serveur, l’historique, le Referer.
Frontière 3 : l’origine. Le navigateur applique la même politique d’origine (same-origin policy) : un script de evil.example ne peut pas lire les réponses de api.example.com. Mais il peut déclencher des requêtes avec vos cookies joints. C’est exactement l’espace que le CSRF exploite, et que SameSite + un jeton applicatif ferment.
De ces frontières découlent les choix de stockage :
| Stockage | XSS | CSRF | Fuite réseau | Verdict |
|---|---|---|---|---|
Cookie HttpOnly; Secure; SameSite | Protégé (JS ne lit pas) | À couvrir (SameSite + jeton) | Protégé (HTTPS) | Recommandé pour sessions et RT |
localStorage | Volable | Non applicable | Protégé en transit | Interdit pour tout secret |
| Token en URL | Volable (logs, historique) | Non applicable | Fuit dans Referer/logs | Interdit |
| AT en mémoire (variable JS) | Volable mais non persistant | Non applicable | Protégé | Acceptable, durée courte |
Les JWT permettent un mode stateless pratique mais exigent de penser la révocation. Une rotation de refresh tokens avec liste de révocation évite de confondre simplicité et sécurité. Les cookies en front doivent être protégés contre XSS/CSRF ; les tokens en stockage Web ne le sont pas. Préférez des sessions côté serveur pour les applications sensibles et gardez les durées de vie raisonnables.
Mini‑exercice : écrivez un flux « login » qui bloque après 5 tentatives ratées pendant 15 minutes, renouvelle l’identifiant de session à la connexion, et invalide les sessions actives lors d’un changement de mot de passe.
#Flows : login sécurisé et OAuth2/OIDC
- Sessions sensibles : cookies HttpOnly/Secure/SameSite + rotation d’ID à la connexion.
- JWT :
aud/issstricts,expcourts, scopes minimaux, révocation via rotation de RT. - Lockout : 5 tentatives/15min, backoff, captcha si nécessaire, alerte sur anomalies.
#Diagrammes : deux modèles d’auth
#Bonnes pratiques clés
- Hashage robuste (Argon2/bcrypt) avec paramètres de coût révisés dans le temps (migration progressive).
- Renouvellement de l’identifiant de session après authentification pour éviter la fixation de session.
- Cookies de session
HttpOnly,Secure,SameSite=Lax/Strict; durée raisonnable ; rotation en cas de suspicion. - JWT :
expcourt ; validation d’audience (aud) et d’émetteur (iss) ;scopeminimal ; révocation via rotation de refresh + liste. - Limiter les tentatives (5/15 min), backoff, captchas si nécessaire ; journaux structurés et alerte en cas d’activité anormale.
#Rotation de refresh tokens (stateless)
#Exemples de code pratiques
#Renouvellement d’ID de session (Express/Node)
1import session from 'express-session'2import type { Request, Response } from 'express'3import argon2 from 'argon2'4import RedisStore from 'connect-redis'5import { redis } from './redis'6 7export async function login(req: Request, res: Response) {8 const { email, password } = req.body9 const user = await usersRepo.findByEmail(email)10 if (!user) return res.status(401).end()11 const ok = await argon2.verify(user.passwordHash, password)12 if (!ok) return res.status(401).end()13 14 // Anti-fixation: régénérer l'ID de session après auth#Validation JWT robuste côté API (JOSE)
1import { jwtVerify, createRemoteJWKSet } from 'jose'2 3const issuer = 'https://auth.example.com'4const audience = 'my-api'5const JWKS = createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`))6 7export async function authenticateBearer(token: string) {8 const { payload, protectedHeader } = await jwtVerify(token, JWKS, {9 algorithms: ['RS256'],10 issuer,11 audience,12 maxTokenAge: '10m', // limite l'âge effectif du token13 })14 #CSRF : double-submit cookie + en-tête personnalisée
1import crypto from 'node:crypto'2import cookieParser from 'cookie-parser'3app.use(cookieParser())4 5// Émettre un cookie CSRF non HttpOnly + renvoyer la valeur (optionnel)6app.get('/csrf', (req, res) => {7 const token = crypto.randomUUID()8 res.cookie('csrf', token, {9 httpOnly: false, sameSite: 'lax', secure: process.env.NODE_ENV === 'production', path: '/'10 })11 res.json({ token })12})13 14// Vérification sur endpoints mutateursLe double-submit fonctionne parce que l’attaquant cross-site peut forcer l’envoi du cookie (le navigateur le joint), mais ne peut pas lire sa valeur pour la recopier dans l’en-tête x-csrf-token. La politique d’origine ferme la lecture ; le jeton ferme l’écriture.
Solution
Pourquoi SameSite=Lax suffit souvent ?
Les navigateurs ne joignent pas les cookies cross-site lors de la plupart des requêtes de navigation si SameSite=Lax. Des cas bord (téléchargements, anciennes versions) existent : combinez avec un jeton anti‑CSRF applicatif.
#Quiz éclair
#Checklist déploiement auth
- Hashage Argon2/bcrypt avec paramètres de coût revus régulièrement ; migration progressive.
- Rotation d’ID de session à la connexion ; cookie
HttpOnly/Secure/SameSiteconfiguré. - Lockout : 5 tentatives/15 min, backoff ; alertes sur anomalies.
- JWT :
iss/audstricts,expcourts,scopeminimal, liste de révocation parjti. - Flux OAuth2 : PKCE (S256), rotation des refresh tokens, liste de révocation, durées de vie courtes.
- Anti‑CSRF : SameSite + jeton applicatif sur requêtes mutatrices.
- Journaux structurés : traceId corrélé, événements de sécurité (login, reset pwd, changement MFA).
#Erreurs fréquentes à éviter
#Mot de passe oublié (flow minimal)
Correction guidée de l’exercice
- Compteur par identité+IP (Redis) avec fenêtre glissante (5/15 min) et backoff.
- Après succès, regenerate la session puis associer
userIdet émettre le cookie. - Sur changement de mot de passe, supprimer les sessions serveur et ajouter les
jtiactifs à la liste de révocation.