Sessions serveur et cookies
État serveur, jeton opaque, attributs du cookie.
Objectifs
À la fin de cette leçon, vous saurez :
- décrire le mécanisme complet d'une session applicative ;
- expliquer chaque attribut du cookie de session ;
- reconnaître ce modèle dans Devmind.
🔗 Pour vous rafraîchir la mémoire : guards et contrôle d'accès · encodage, hachage, chiffrement
Le flux complet
1. login (identifiants vérifiés)
2. le serveur CRÉE une session en base : id → user_id, expiration
3. réponse : Set-Cookie: session=<jeton>; HttpOnly; Secure; SameSite=Lax
4. chaque requête suivante : Cookie: session=<jeton>
5. le serveur cherche le jeton en base → sait qui parle
6. logout : SUPPRESSION de la ligne en base
Deux moitiés : l'état côté serveur (la table sessions) et un simple identifiant côté client. Le cookie ne contient ni profil ni information signée : sa seule valeur est de désigner une ligne en base.
Pourquoi révocable par construction
La session vit en base : supprimer la ligne déconnecte immédiatement l'utilisateur, partout — même si son navigateur garde encore le cookie. C'est la différence décisive avec les JWT auto-porteurs (prochaine leçon) : une session peut être tuée, un jeton signé reste valide jusqu'à expiration.
Le projet Devmind applique exactement cela : table sessions (hash du jeton, expiration), cookie dm_session ne contenant qu'un jeton aléatoire, logout = DELETE en base.
Les attributs du cookie, un par un
Set-Cookie: dm_session=abc123;
HttpOnly; ← invisible au JavaScript (anti-XSS)
Secure; ← uniquement via HTTPS
SameSite=Lax; ← non envoyé depuis un site tiers (anti-CSRF basique)
Max-Age=604800;← durée de vie
Path=/; ← envoyé pour tout le site
Chaque attribut ferme une attaque précise ; les oublier rouvre chacune. SameSite=None (nécessaire cross-site, comme dans Devmind dev sur deux ports) exige alors Secure et des protections CSRF supplémentaires.
Le hash du jeton en base
Détail d'implémentation qui compte : on stocke sha256(jeton), jamais le jeton lui-même. Une fuite de base ne permet donc pas d'usurper les sessions existantes — même logique que pour les mots de passe : ce qui est sensible se hache, toujours.
Rôles et permissions : la suite logique
Savoir QUI se connecte (authentification) n'est que la moitié ; il faut décider ce qu'il a le droit de FAIRE (autorisations). Deux notions complètent la session :
- le rôle : une catégorie d'utilisateurs — chez Devmind :
STUDENTetADMIN; - les permissions : les actions concrètes autorisées — publier une révision, modérer une proposition…
Le modèle le plus simple associe le rôle à la session côté serveur : lors du login, on lit le rôle stocké en base avec l'utilisateur, et chaque route sensible vérifie « ce rôle suffit-il ici ? ». Point non négociable : cette vérification vit dans l'API, jamais seulement dans le frontend — l'interface peut masquer un bouton, seul le serveur refuse.
C'est exactement le duo Devmind : le rôle voyage avec la session (jamais dans un cookie lisible), et un RolesGuard côté NestJS bloque /api/admin/* pour un non-admin (mécanisme détaillé au chapitre 35).
Exercice
- Dessinez le flux login → requêtes protégées → logout.
- Pourquoi le jeton aléatoire doit-il être long (32 octets+) ?
- Que gagne-t-on à hacher le jeton en base ?
Résumé
- Session = état serveur + identifiant opaque en cookie.
- Attributs du cookie = trois attaques fermées.
- Révocabilité immédiate : LA raison d'être des sessions serveur.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Question 2. La sécurité repose sur l'imprévisibilité : 256 bits d'aléa rendent l'énumération physiquement impossible. Un compteur ou un timestamp serait deviné en secondes.
Question 3. En cas de fuite de la base, l'attaquant obtient des empreintes sans les jetons : impossible de forger un cookie valide. Coût : un sha256 à chaque vérification — négligeable.