Aller au contenu principal

Backend pratique · L2 · Section 3/6

Authentification et sessions

Progression

Points d’expérience : XPSérie de jours consécutifs : · —Progression du module : — / —compris

#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 :

StockageXSSCSRFFuite réseauVerdict
Cookie HttpOnly; Secure; SameSiteProtégé (JS ne lit pas)À couvrir (SameSite + jeton)Protégé (HTTPS)Recommandé pour sessions et RT
localStorageVolableNon applicableProtégé en transitInterdit pour tout secret
Token en URLVolable (logs, historique)Non applicableFuit dans Referer/logsInterdit
AT en mémoire (variable JS)Volable mais non persistantNon applicableProté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

1/5
1/5
  • Sessions sensibles : cookies HttpOnly/Secure/SameSite + rotation d’ID à la connexion.
  • JWT : aud/iss stricts, exp courts, 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

Client
BFF/API
Store session
1. POST /login (email, pwd)
2. Créer session (id→userId)
3. Set‑Cookie sid; HttpOnly; SameSite
4. GET /me (cookie sid)
SPA
AuthZ Server
API
1. Code + PKCE (authorize)
2. Échange code↔token (code_verifier)
3. GET /me (Bearer AT)
4. 200

#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 : exp court ; validation d’audience (aud) et d’émetteur (iss) ; scope minimal ; 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)

Client
AuthZ
API
1. POST /token (code_verifier)
2. 200 { AT, RT }
3. GET /me (Bearer AT)
4. 200
5. POST /token (refresh_token)
6. 200 { new AT, new RT } (rotate & revoke)
7. GET /protected (Bearer new AT)
8. 200

#Exemples de code pratiques

#Renouvellement d’ID de session (Express/Node)

tsts

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)

tsts

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 
tsts

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 mutateurs

Le 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

Où stocker un refresh token côté navigateur pour une appli sensible ?
Où stocker un refresh token côté navigateur pour une appli sensible ?
Quelles validations minimales pour accepter un JWT côté API ?
Quelles validations minimales pour accepter un JWT côté API ?
Pourquoi le double-submit cookie arrête-t-il le CSRF ?
Pourquoi le double-submit cookie arrête-t-il le CSRF ?

#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/SameSite configuré.
  • Lockout : 5 tentatives/15 min, backoff ; alertes sur anomalies.
  • JWT : iss/aud stricts, exp courts, scope minimal, liste de révocation par jti.
  • 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)

1/5
Correction guidée de l’exercice
  1. Compteur par identité+IP (Redis) avec fenêtre glissante (5/15 min) et backoff.
  2. Après succès, regenerate la session puis associer userId et émettre le cookie.
  3. Sur changement de mot de passe, supprimer les sessions serveur et ajouter les jti actifs à la liste de révocation.