Attributs du cookie de session
- Accueil
- Développement, applications & chaîne logicielle
- Attributs du cookie de session
Attributs du cookie de session
Section intitulée « Attributs du cookie de session »Un cookie de session est un secret au porteur : qui présente l’identifiant est pris pour le compte, sans autre question. Les attributs de l’en-tête HTTP (Hypertext Transfer Protocol) Set-Cookie règlent par où ce secret peut fuir et depuis où il peut être rejoué ; ils ne décident ni de sa durée de validité réelle ni de sa révocation. Cette page trie ce que chaque attribut garantit, ce qu’il ne garantit pas, et ce qui doit venir du serveur.
Après avoir montré sa carte à l’entrée d’un festival, on reçoit un bracelet : plus besoin de ressortir ses papiers à chaque stand. Celui qui récupère ce bracelet passe pour son propriétaire, sans rien d’autre à prouver. Toute la question est de fabriquer un bracelet qui ne se copie pas, ne se prête pas et finit par ne plus rien ouvrir.
→ Lire l’explication complète de la marmotte
Ce que Secure, HttpOnly et SameSite garantissent, et ce qu’ils laissent passer
Section intitulée « Ce que Secure, HttpOnly et SameSite garantissent, et ce qu’ils laissent passer »La position défendue ici : les attributs ferment des chemins de fuite, ils ne protègent pas la session. La protection se joue côté serveur, avec un identifiant imprévisible, une expiration appliquée par le serveur et une révocation qui supprime réellement quelque chose. Le compromis central est connu : chaque durcissement se paie en friction. SameSite=Strict casse les liens entrants, une expiration courte multiplie les authentifications, la révocation immédiate coûte une lecture en magasin de sessions à chaque requête. La recommandation : payer la lecture en magasin sans discuter, garder Lax pour le cookie de session, et raccourcir l’inactivité plutôt que de rêver à un attribut miracle.
Les textes de référence sont la RFC (Request for Comments) 6265 et sa révision à l’IETF (Internet Engineering Task Force), dite « rfc6265bis », encore à l’état de brouillon en relecture finale avant publication (version 22, décembre 2025), qui apporte SameSite, les préfixes de nom et plusieurs durcissements. Côté pratique, l’OWASP (Open Worldwide Application Security Project) publie la Session Management Cheat Sheet et l’ASVS (Application Security Verification Standard), dont un chapitre entier porte sur la gestion de session.
Secure interdit au navigateur de joindre le cookie à une requête qui ne passe pas par HTTPS (HTTP sur TLS, Transport Layer Security). Il protège la confidentialité de l’identifiant sur le réseau, rien de plus. Dans la RFC 6265 d’origine, il ne protège même pas son intégrité : une réponse HTTP non chiffrée, forgeable par quiconque tient le réseau, pouvait écraser un cookie Secure. La révision corrige ce point en interdisant à une origine non sécurisée de poser ou de remplacer un cookie portant cet attribut.
Ce que Secure ne fait pas : empêcher la première requête non chiffrée de partir. C’est le travail de HSTS (HTTP Strict Transport Security), qui force le navigateur à ne parler qu’en HTTPS au domaine ; le reste de la chaîne est décrit dans TLS expliqué.
HttpOnly
Section intitulée « HttpOnly »HttpOnly retire le cookie des interfaces non HTTP du navigateur, en pratique document.cookie en JavaScript. Un script injecté par XSS (Cross-Site Scripting) ne peut plus lire l’identifiant pour l’envoyer ailleurs. Il peut en revanche tout faire depuis la page : chaque requête qu’il émet vers l’application part avec le cookie, joint par le navigateur. HttpOnly empêche l’exfiltration de la session, pas son usage sur place. Il figure dans tous les rapports d’audit, entre l’en-tête manquant et la bannière de version : le poser prend une ligne, croire qu’il règle le XSS prend des années à désapprendre.
Une attaque connue contourne aussi la protection en écriture. Un script ne peut pas écraser un cookie HttpOnly, mais le navigateur évince les cookies les plus anciens quand leur nombre par domaine dépasse sa limite. Le script inonde donc le pot de cookies, fait tomber l’original, puis pose le sien sous le même nom. La contre-mesure n’est pas un attribut : c’est la régénération de l’identifiant à l’authentification, traitée dans la page sur la fixation de session, et l’élimination du XSS lui-même (mécanisme, variantes et défenses).
SameSite
Section intitulée « SameSite »SameSite décide si le cookie accompagne une requête déclenchée depuis un autre site. Strict ne le joint jamais dans ce cas. Lax le joint uniquement lors d’une navigation de premier niveau avec une méthode sûre (un clic sur un lien, donc un GET), pas sur un formulaire POST ni sur une sous-ressource. None le joint partout et exige Secure. C’est une défense en profondeur contre le CSRF (Cross-Site Request Forgery), la requête forgée par un site tiers qui profite du cookie de la victime. Sa limite tient dans le mot « site », qui ne veut pas dire « origine » : le sujet de la section suivante.
Le schéma résume quelle attaque chaque attribut arrête, et surtout les lignes où aucun attribut ne répond. Il y est question de CSP (Content Security Policy), l’en-tête qui restreint les scripts qu’une page a le droit d’exécuter.
Site contre origine : Domain, Path et les préfixes __Host- et __Secure-
Section intitulée « Site contre origine : Domain, Path et les préfixes __Host- et __Secure- »Une origine, c’est le triplet schéma, hôte, port. Un site, c’est le domaine enregistrable : le suffixe public (.fr, .co.uk) plus un label, auquel la révision ajoute le schéma. app.exemple.fr et blog.exemple.fr sont deux origines et un seul site. Conséquence directe : un sous-domaine compromis, par XSS ou par reprise d’un enregistrement DNS (Domain Name System) laissé à l’abandon, émet des requêtes same-site. SameSite=Strict les laisse passer avec le cookie, sans sourciller.
Les cookies ignorent aussi le port. Deux services sur le même hôte, l’un en 443 et l’autre en 8443, partagent le même pot. Héberger une console d’administration et un outil de test sur le même nom d’hôte revient à leur donner le même trousseau.
Domain élargit, il ne restreint pas
Section intitulée « Domain élargit, il ne restreint pas »Sans attribut Domain, le cookie est lié à l’hôte exact qui l’a posé. Avec Domain=exemple.fr, il part vers tous les sous-domaines. L’attribut élargit donc la portée, à rebours de l’intuition, et un cookie de session ne devrait jamais le porter.
Le vrai danger est en écriture. N’importe quel sous-domaine peut poser un cookie avec Domain=exemple.fr, y compris sous le nom du cookie de session. Le serveur reçoit alors deux cookies homonymes sans aucun moyen de savoir lequel il a émis : les attributs ne remontent pas dans l’en-tête Cookie. C’est le « cookie tossing », voie royale vers la fixation de session.
Path n’est pas une frontière
Section intitulée « Path n’est pas une frontière »Path limite l’envoi du cookie à une branche de l’arborescence. La RFC 6265 le dit sans détour : on ne peut pas s’y fier pour la sécurité. Deux applications sur le même hôte, sous /a et /b, partagent une origine ; un script de l’une charge l’autre dans un cadre et y lit ce qu’il veut. Isoler deux applications demande deux hôtes, pas deux chemins.
Les préfixes de nom
Section intitulée « Les préfixes de nom »Les préfixes transforment le nom du cookie en contrat que le navigateur vérifie à l’écriture. Avec __Secure-, le cookie doit porter Secure et venir d’une origine sécurisée. Avec __Host-, il doit en plus avoir Path=/ et ne porter aucun attribut Domain. Un cookie __Host- est donc lié à un hôte exact et aucun sous-domaine voisin ne peut le poser ni l’écraser. Côté navigateur, c’est le seul mécanisme qui ferme le cookie tossing, et il coûte sept caractères.
Deux conditions pour que le contrat tienne. Le serveur ne doit accepter que le nom préfixé : garder un nom de repli sans préfixe « pour la compatibilité » annule tout. Et le préfixe ne protège pas contre un script de la même origine, qui peut poser un cookie __Host- valide. Contre celui-là, retour à la case XSS.
Choisir SameSite : Strict, Lax ou None
Section intitulée « Choisir SameSite : Strict, Lax ou None »Strict a un prix que les fiches de durcissement oublient de mentionner : l’utilisateur qui clique sur un lien reçu par courriel arrive sans cookie, donc déconnecté en apparence, jusqu’à la navigation suivante. Le retour d’un fournisseur d’identité subit le même sort. Lax laisse passer ces navigations, ce qui suppose une règle absolue côté application : aucun GET ne modifie l’état. Un lien de suppression en GET sous Lax, c’est un CSRF avec une étape de moins.
L’attribut s’écrit toujours explicitement. Chrome applique Lax aux cookies sans attribut depuis sa version 80, avec une tolérance : pendant les deux minutes qui suivent sa création, un tel cookie part quand même sur un POST intersite de premier niveau. Ce défaut n’est pas uniforme d’un navigateur à l’autre ; s’appuyer dessus revient à déléguer une décision de sécurité à un réglage qu’on ne maîtrise pas.
L’arbre ci-dessous donne la valeur à retenir selon deux questions : usage embarqué chez un tiers, puis présence de liens entrants.
Un cas particulier mérite d’être isolé. Quand un fournisseur d’identité renvoie sa réponse par un formulaire POST intersite, Lax ne joint pas le cookie qui porte l’état de la demande d’authentification. Ce cookie-là, distinct du cookie de session, a besoin de SameSite=None; Secure et d’une durée de vie de quelques minutes. Affaiblir le cookie de session pour faire fonctionner la fédération est l’erreur classique.
Un schéma à deux cookies donne le meilleur des deux mondes : un cookie Lax qui ouvre la session en lecture, un second en Strict exigé pour les opérations sensibles. Le lien entrant affiche la page ; le virement demande le cookie que seul un parcours interne au site transporte.
Reste Partitioned, issu de la proposition CHIPS (Cookies Having Independent Partitioned State). Il range le cookie dans un compartiment propre au site de premier niveau qui embarque le contenu : le même service intégré chez deux sites reçoit deux cookies indépendants. Il exige Secure et n’a de sens que pour un usage tiers. Le contexte pèse : Safari bloque les cookies tiers par défaut et Firefox les cloisonne par site (Total Cookie Protection). Une session qui dépend d’un cookie tiers non partitionné est déjà cassée chez une partie des utilisateurs.
Durée de vie : Max-Age, Expires et expiration côté serveur
Section intitulée « Durée de vie : Max-Age, Expires et expiration côté serveur »Max-Age (en secondes) et Expires (une date) demandent au navigateur de conserver le cookie ; si les deux sont présents, Max-Age l’emporte. La révision demande aux navigateurs de plafonner cette durée à 400 jours. Sans aucun des deux, le cookie est dit « de session » et disparaît à la fermeture du navigateur, navigateur que plus personne ne ferme depuis l’invention de la restauration d’onglets, laquelle restaure aussi ces cookies.
Dans tous les cas, cette durée est une consigne donnée au client. Un identifiant copié n’a pas de Max-Age : il vit aussi longtemps que le serveur l’accepte. L’expiration réelle est donc double et côté serveur :
- l’expiration d’inactivité, qui ferme une session sans requête depuis un délai donné ;
- l’expiration absolue, qui ferme une session à un âge donné, activité ou non.
La seconde est celle qu’on oublie, et c’est elle qui borne un vol : sans plafond absolu, un attaquant qui émet une requête toutes les dix minutes garde la session indéfiniment. La Session Management Cheat Sheet de l’OWASP donne des ordres de grandeur : 2 à 5 minutes d’inactivité pour une application à forte valeur, 15 à 30 minutes pour un risque faible, et 4 à 8 heures en absolu pour un usage de journée de bureau. Le Max-Age du cookie, s’il existe, s’aligne sur l’expiration absolue et ne la dépasse jamais.
Révocation : session à état contre jeton autoporté dans un cookie
Section intitulée « Révocation : session à état contre jeton autoporté dans un cookie »Deux façons de ranger une session dans un cookie, et la question qui les départage est celle de la révocation.
La session à état place dans le cookie un identifiant opaque, sans signification. Tout le reste (compte, heures, privilèges) vit dans un magasin côté serveur. Révoquer, c’est supprimer l’entrée : effet à la requête suivante.
Le jeton autoporté place dans le cookie un contenu signé, typiquement un JWT (JSON Web Token), que le serveur valide sans consulter quoi que ce soit ; le format de signature est décrit dans la page JWS. Ce jeton reste valide jusqu’à son échéance, quoi qu’il arrive. La déconnexion efface le cookie du navigateur légitime et ne change rien pour la copie volée. Le « sans état » se vend très bien sur une slide ; la slide suivante, celle de la liste de révocation consultée à chaque requête, réintroduit l’état par la porte de service.
La recommandation tranche : pour une session de navigateur, identifiant opaque et magasin côté serveur. Le jeton autoporté en cookie ne se défend qu’avec une durée de vie de quelques minutes et un renouvellement adossé à un état serveur, ce qui est le modèle décrit dans la durée de vie des jetons OAuth. À ce prix, autant garder la session à état.
Le cycle de vie complet, avec les deux contrôles d’expiration et la révocation par compte :
La dernière ligne impose une contrainte de modèle de données : le magasin doit être interrogeable par compte, pas seulement par identifiant. Sans cet index, « fermer toutes les sessions de ce compte » devient un parcours complet du magasin, donc une fonction que personne n’implémente. Vingt ans de sessions web apprennent une chose : la déconnexion est la fonctionnalité la moins testée d’une application, juste devant la restauration de sauvegarde.
Exemple d’en-tête Set-Cookie pour un cookie de session
Section intitulée « Exemple d’en-tête Set-Cookie pour un cookie de session »L’en-tête ci-dessous correspond à la recommandation de cette page pour une application de premier niveau avec liens entrants.
Set-Cookie: __Host-sid=3q2-7wAAb0x9Jm1PpQeXZg; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800
# __Host-sid préfixe vérifié par le navigateur : Secure, Path=/ et aucun Domain exigés# valeur 22 caractères base64url, soit 128 bits tirés d'un générateur cryptographique# Path=/ imposé par le préfixe ; Path ne sert pas de cloison# Secure jamais joint à une requête hors HTTPS# HttpOnly invisible pour document.cookie# SameSite=Lax joint aux navigations GET de premier niveau venues d'un autre site, pas aux POST# Max-Age=28800 8 heures, aligné sur l'expiration absolue appliquée par le serveur# pas de Domain cookie lié à l'hôte exact, non partagé avec les sous-domainesLa valeur ne contient aucune information : ni identifiant de compte, ni horodatage, ni rôle. Le nom ne trahit pas non plus le cadre applicatif utilisé, ce que la cheat sheet de l’OWASP recommande aussi. Pour une application à forte valeur, Max-Age disparaît et l’expiration d’inactivité côté serveur descend à quelques minutes.
Prérequis de plateforme et conditions d’exploitation
Section intitulée « Prérequis de plateforme et conditions d’exploitation »Avant de poser le premier attribut, quatre choses doivent exister.
- HTTPS sur tout le domaine, avec HSTS étendu aux sous-domaines. Un seul hôte servi sans chiffrement suffit à rouvrir la question.
- Un hôte dédié à l’application. Le contenu déposé par les utilisateurs et les services à confiance réduite vont sur un autre domaine enregistrable, pas sur un sous-domaine voisin.
- Un schéma correctement perçu derrière un proxy inverse. Quand TLS se termine sur le proxy, l’application voit du HTTP et son cadre applicatif peut omettre
Secure; l’en-tête de schéma transmis par le proxy ne doit être cru que s’il vient de ce proxy. - Un magasin de sessions partagé entre les instances, avec expiration native des entrées et accès par compte.
En exploitation, les points qui reviennent :
- Identifiant. La Session Management Cheat Sheet de l’OWASP fixe un plancher de 64 bits d’entropie ; en générer 128 avec le générateur cryptographique du système ne coûte rien et clôt le débat. Le magasin conserve un condensat de l’identifiant, pas l’identifiant : une fuite du magasin ne livre alors aucune session rejouable.
- Secrets. Si le cadre applicatif signe ou chiffre le contenu du cookie, cette clé est un secret de production. Elle se fait tourner avec deux clés acceptées en lecture pendant la transition, et elle n’a rien à faire dans le dépôt (prévention des secrets dans le code source).
- Rotation. Identifiant neuf à l’authentification, à chaque élévation de privilège et après un second facteur. L’ancien est supprimé du magasin, pas laissé à expirer.
- Supervision. Journaliser création, renouvellement et fin de session avec un condensat de l’identifiant, jamais sa valeur. Surveiller le nombre de sessions par compte, l’usage simultané d’un identifiant depuis deux contextes distincts et les identifiants inconnus présentés en rafale.
- Sauvegarde et reprise. Le magasin de sessions ne se restaure pas. Le perdre impose à tout le monde de se reconnecter, ce qui est un désagrément. Restaurer une copie ancienne ressuscite des sessions révoquées, ce qui est un incident.
Ce qui reste à la charge de l’application : anti-CSRF, CSP, régénération
Section intitulée « Ce qui reste à la charge de l’application : anti-CSRF, CSP, régénération »Aucun attribut ne couvre les points suivants, et les supposer couverts est l’erreur la plus répandue.
Le jeton anti-CSRF reste nécessaire sur toute requête qui modifie l’état. SameSite ne voit pas les requêtes same-site d’un sous-domaine compromis, et Lax laisse passer les GET. Les deux mécanismes se complètent ; aucun ne remplace l’autre.
La CSP et l’échappement des sorties traitent le XSS, qu’aucun attribut de cookie n’arrête une fois le script dans la page. La régénération de l’identifiant traite la fixation. L’entropie de l’identifiant traite la devinette. Le contrôle d’accès par objet reste entier : une session valide ne dit rien du droit à consulter telle ressource (BOLA et contrôle d’accès).
Enfin, rien de tout cela ne résiste à un poste compromis. Un logiciel voleur de données copie le pot de cookies sur disque, et une extension de navigateur dotée de la permission adéquate lit les cookies HttpOnly comme les autres (sécurité des extensions de navigateur). Contre le rejeu d’un identifiant volé sur le poste, seules l’expiration courte, la révocation et la détection d’usage anormal côté serveur répondent.
SameSite=Strict dispense-t-il du jeton anti-CSRF ?
Section intitulée « SameSite=Strict dispense-t-il du jeton anti-CSRF ? »Non. Strict raisonne par site, pas par origine : une requête émise depuis un sous-domaine du même domaine enregistrable part avec le cookie. Le jeton anti-CSRF, lui, est lié à la session et inconnu du sous-domaine voisin. SameSite réduit l’exposition, le jeton ferme le cas restant.
Vaut-il mieux ranger le jeton de session dans le stockage local du navigateur ?
Section intitulée « Vaut-il mieux ranger le jeton de session dans le stockage local du navigateur ? »Non pour une session de navigateur. Le stockage local n’a aucun équivalent de HttpOnly : tout script de la page, y compris une dépendance tierce, lit le jeton et l’emporte pour le rejouer ailleurs. Un cookie HttpOnly oblige au moins l’attaquant à agir depuis la page de la victime, pendant qu’elle est ouverte.
Effacer le cookie à la déconnexion vaut-il révocation ?
Section intitulée « Effacer le cookie à la déconnexion vaut-il révocation ? »Non. Renvoyer le cookie avec Max-Age=0 le retire du navigateur qui a cliqué sur « déconnexion », et de lui seul. Une copie de l’identifiant reste acceptée tant que l’entrée existe dans le magasin. La déconnexion supprime d’abord l’entrée côté serveur, puis efface le cookie par politesse.
🐝 Ce qui arrive si on s’en passe
Section intitulée « 🐝 Ce qui arrive si on s’en passe »Sans ces attributs ni état côté serveur, les défauts se composent au lieu de s’additionner. L’identifiant voyage sur la première requête non chiffrée, se lit depuis n’importe quel script tiers chargé par la page et accompagne les requêtes forgées par un site quelconque ; une fois copié, il reste valable tant que personne ne redémarre le service, puisque rien ne le périme. Le changement de mot de passe, réflexe de toute réponse à incident, ne déloge alors personne : l’attaquant garde sa session pendant que la victime croit avoir repris la main. Côté exploitation, la perte est double : aucun inventaire des sessions ouvertes, donc aucune réponse à la question « qui est connecté sur ce compte, depuis quand », et aucun moyen de couper un accès sans couper tout le monde.
🦫 Explication de la marmotte 🍫
Section intitulée « 🦫 Explication de la marmotte 🍫 »Quand une personne se connecte à un site, le serveur fabrique une longue suite de caractères tirée au hasard et la confie au navigateur. Le navigateur la renvoie ensuite à chaque page demandée : c’est ce qui permet au serveur de reconnaître la personne sans redemander le mot de passe. Qui détient cette suite est donc pris pour le titulaire du compte. Le serveur accompagne l’envoi de consignes que le navigateur applique : ne transmettre la suite que sur une connexion chiffrée, la cacher aux programmes qui tournent dans la page, ne pas la joindre quand la demande vient d’un autre site, refuser qu’une adresse voisine la remplace. Ces consignes réduisent les occasions de vol, mais elles ne valent que dans un navigateur sain : un programme malveillant installé sur l’ordinateur peut toujours copier la suite. La vraie défense se tient donc sur le serveur. Il garde une fiche pour chaque connexion ouverte, avec l’heure de création et l’heure de la dernière demande. À chaque demande, il vérifie que la fiche existe encore, qu’elle n’est pas restée inutilisée trop longtemps et qu’elle n’est pas trop ancienne. Pour couper un accès, il supprime la fiche : la suite copiée ne correspond plus à rien et le voleur est renvoyé vers la page de connexion. Sans fiche côté serveur, rien ne permet de couper un accès avant sa date de fin.
À lire aussi
- Sécuriser un contrat API-first dès la conceptionConcevoir un contrat d’API comme une frontière de confiance, avec authentification, autorisation, validation et exploitation sécurisées.
- JWE : chiffrer un jeton JSON sans se tromperComment fonctionne JSON Web Encryption, quels algorithmes retenir, quels pièges de production évitent qu'un jeton chiffré ne devienne une fausse garantie.
- OWASP Top 10 ASVS ZAP et sécurité applicativePrésentation de l’OWASP, de son mandat communautaire, de ses référentiels de sécurité applicative et de leur exploitation en architecture.
- Comment lire un rapport OWASP Top 10Lire un rapport de scan OWASP Top 10 sans confondre signal technique, risque exploitable et bruit de détection.
Pages voisines
La citent
- Comment lire un rapport OWASP Top 10
- Durcir les postes de développeurs contre le vol de code et secrets
- JavaScript et SQL côté web, ce qu'il faut savoir des deux langages
Attributs du cookie de session
Elle cite
- Lien dans les deux sens :Comment empêcher une attaque de fixation de session
- Lien dans les deux sens :Cross-site scripting (XSS) : mécanisme, variantes et défenses
- Lien dans les deux sens :Gérer la durée de vie des jetons OAuth
- Lien dans les deux sens :OIDC, SAML et OAuth 2.1 en fédération
- Lien dans les deux sens :Politique de sécurité des extensions navigateur en entreprise
- JWS : signer et sécuriser vos échanges JSON
- Prévenir les secrets codés en dur dans Git
- Comprendre TLS : mécanismes, garanties et limites
- Concevoir une défense en profondeur par couches
: les deux pages se citent l’une l’autre.
