# Sécurité des cookies (/fr/docs/web-security/security-headers/cookie-security)



Les cookies portent la session. Après la connexion, le serveur pose un cookie,
le navigateur l'attache à chaque requête correspondante, et quiconque détient
cette valeur de cookie est connecté en tant que l'utilisateur. Il n'existe pas
de header « sécurité des cookies » unique ; la protection tient dans une poignée
d'attributs sur le header de réponse `Set-Cookie` lui-même.

Ces attributs (`Secure`, `HttpOnly`, `SameSite`, les préfixes de nom `__Host-`
et `__Secure-`, et `Partitioned`) décident si le cookie peut être lu sur le
réseau, volé par un script injecté, rejoué par une requête cross-site ou planté
par un sous-domaine. Chacun tient en quelques caractères sur la même ligne, et
les omettre est ce qui rend une session dérobable.

Voici un cookie de session durci tel que vous le déploieriez :

```http
Set-Cookie: __Host-session=<value>; Secure; HttpOnly; SameSite=Lax; Path=/
```

## Valeurs et ce que fait chacune [#valeurs-et-ce-que-fait-chacune]

| Attribut                            | Statut          | Description                                                                                                                                                                            |
| ----------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Secure`                            | ✅ Bon           | N'envoyer le cookie qu'en HTTPS, jamais sur une requête HTTP en clair. Obligatoire pour les cookies de session.                                                                        |
| `HttpOnly`                          | ✅ Bon           | Cache le cookie à JavaScript. Les scripts ne peuvent ni lire ni exfiltrer la valeur.                                                                                                   |
| `SameSite=Strict`                   | ✅ Bon           | N'envoie que sur les requêtes same-site. La plus forte protection CSRF, mais abandonne la session sur les liens cross-site entrants.                                                   |
| `SameSite=Lax`                      | ✅ Bon           | Requêtes same-site plus navigations de premier niveau cross-site avec méthodes sûres (clics sur un lien). Le défaut pratique pour les sessions.                                        |
| `SameSite=None`                     | ❌ Risqué        | Envoie sur toutes les requêtes cross-site. Légitime uniquement pour les intégrations cross-site, exige `Secure`, et `Partitioned` convient mieux à l'état d'un widget.                 |
| (pas de `SameSite`)                 | ❌ Risqué        | Le défaut varie selon le navigateur, et le Lax par défaut de Chrome garde une exception de 2 minutes pour les POST cross-site. Réglez toujours l'attribut explicitement.               |
| préfixe `__Host-`                   | ✅ Bon           | Le navigateur rejette le cookie sauf s'il a `Secure`, aucun `Domain` et `Path=/`. Le lie à un seul hôte exactement.                                                                    |
| préfixe `__Secure-`                 | ✅ Bon           | Le navigateur rejette le cookie sauf s'il est posé avec `Secure` depuis une origine sécurisée.                                                                                         |
| préfixes `__Http-` / `__Host-Http-` | 🧪 Expérimental | Exigent en plus `HttpOnly`, prouvant que le cookie vient d'un header et jamais d'un script. Dans Chrome et Firefox, pas Safari, en cours de standardisation.                           |
| `Partitioned`                       | ✅ Bon           | Stocke un cookie cross-site par site de premier niveau (CHIPS) pour qu'une intégration garde son état sans devenir un identifiant cross-site. Baseline largement disponible selon MDN. |

### Secure [#secure]

`Secure` indique au navigateur de n'attacher le cookie qu'aux requêtes HTTPS, de
sorte qu'il ne traverse jamais le réseau en clair (les navigateurs lèvent
l'exigence sur localhost). Il restreint la transmission, pas la pose : un
attaquant qui répond à une requête HTTP en clair peut toujours poser des cookies
pour l'hôte, même si un `Set-Cookie` non sécurisé ne peut pas écraser un cookie
`Secure` existant du même nom. Associez-le à
[Strict-Transport-Security](/fr/docs/web-security/security-headers/strict-transport-security)
pour que la requête non sécurisée ne quitte jamais la machine en premier lieu.

### HttpOnly [#httponly]

`HttpOnly` cache le cookie à `document.cookie` et à l'
[API Cookie Store](https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API),
de sorte qu'un script s'exécutant dans la page ne peut pas lire la valeur. Le
navigateur attache toujours le cookie aux requêtes que les scripts déclenchent,
ce qui signifie qu'un code injecté peut agir comme l'utilisateur sur place ; ce
que `HttpOnly` empêche, c'est de copier la session vers l'extérieur pour un usage
ultérieur. Posez-le sur chaque cookie dont JavaScript n'a pas besoin, ce qui,
pour les cookies de session, veut dire tous.

### SameSite [#samesite]

`SameSite` contrôle si le cookie accompagne les requêtes cross-site. `Strict` ne
l'envoie que sur les requêtes same-site. `Lax` ajoute les navigations de premier
niveau cross-site avec méthodes sûres (un lien cliqué, un formulaire GET), mais
jamais les sous-ressources cross-site comme les appels `fetch()`, les images ou
les iframes. `None` l'envoie partout et est rejeté d'emblée sauf si `Secure` est
aussi présent. Ne vous fiez jamais au défaut du navigateur ; il diffère selon le
navigateur (voir la section prise en charge par les navigateurs plus bas).

### Préfixes de cookies [#préfixes-de-cookies]

Les préfixes sont des conventions de nommage que le navigateur fait respecter au
moment où le cookie est posé. Un cookie `__Secure-` doit porter `Secure` et venir
d'une origine sécurisée. Un cookie `__Host-` doit en outre n'avoir aucun attribut
`Domain` et un `Path=/`, ce qui le lie à un seul hôte exactement : les
sous-domaines ne peuvent ni le poser ni le masquer, ce qui ferme la faille de
cookie tossing décrite plus bas. Les préfixes plus récents `__Http-` et
`__Host-Http-` (pris en charge dans Chrome et Firefox, en cours de
standardisation) exigent en plus `HttpOnly`, de sorte que le nom lui-même prouve
que le cookie a été posé par un header et jamais par un script.

### Partitioned [#partitioned]

`Partitioned` fait entrer un cookie cross-site dans un stockage indexé par le
site de premier niveau (la proposition CHIPS), de sorte qu'un widget intégré
garde un état distinct sur chaque site qui l'intègre, au lieu d'un identifiant
unique qui suit l'utilisateur à travers le web. Il exige `Secure` et s'utilise
avec `SameSite=None`, et MDN recommande de le poser avec le préfixe `__Host-`. Il
a atteint Baseline lorsque Firefox et Safari ont rejoint Chrome dans sa prise en
charge.

## Contre quoi cela protège [#contre-quoi-cela-protège]

* **L'interception de session en transit.** `Secure` garde le cookie hors des
  sauts HTTP en clair, où un espion passif sur le chemin pourrait le copier et
  rejouer la session. OWASP le considère comme obligatoire pour les cookies de
  session.
* **Le vol de cookie par XSS.** `HttpOnly` empêche un script injecté de lire la
  valeur de session et de l'envoyer au serveur d'un attaquant. Il n'empêche pas
  le script d'utiliser la session sur place, car le navigateur attache toujours
  le cookie aux requêtes que fait la page ; une
  [politique de sécurité du contenu (CSP)](/fr/docs/web-security/policies/content-security-policy)
  traite l'injection elle-même.
* **La falsification de requête cross-site, en défense en profondeur.**
  `SameSite` retire le cookie de la plupart des requêtes cross-site, ce dont
  abuse le CSRF. Il réduit l'attaque, il ne remplace pas les jetons CSRF (voir
  les pièges plus bas pour comprendre pourquoi, et
  [SameSite contre les tokens CSRF](/fr/blog/samesite-vs-csrf-tokens) pour la
  comparaison complète).
* **Le cookie tossing depuis les sous-domaines.** N'importe quel sous-domaine
  peut normalement planter un cookie auquel l'application parente fera confiance,
  un problème d'intégrité faible que rfc6265bis documente et que la
  [recherche OAuth de Snyk](https://labs.snyk.io/resources/hijacking-oauth-flows-via-cookie-tossing/)
  a transformé en véritables attaques de fixation de session. Le préfixe
  `__Host-` le ferme.

## Risques sans ces attributs [#risques-sans-ces-attributs]

Un cookie de session sans attribut est exposé sur tous les fronts. Il voyage en
clair sur toute requête HTTP en clair vers l'hôte, où quiconque se trouve sur le
chemin réseau peut le copier et détourner la session. Tout script injecté dans
la page peut le lire via `document.cookie` et l'exfiltrer. Chaque requête
cross-site le transporte, ce qui est exactement l'ouverture dont le CSRF a
besoin. Et n'importe quel sous-domaine, y compris un oublié ou vulnérable, peut
planter un cookie sosie que l'application principale acceptera, fixant la victime
dans une session contrôlée par l'attaquant.

## Risques et pièges à l'usage [#risques-et-pièges-à-lusage]

* **`SameSite=None` sans `Secure` n'aboutit jamais.** Chrome, Edge et le Firefox
  actuel refusent silencieusement de stocker le cookie. C'est la première cause
  du « mon cookie cross-site a disparu ».
* **L'exception Lax+POST de 2 minutes de Chrome.** Les cookies sans attribut
  `SameSite` sont encore envoyés sur les POST de premier niveau cross-site
  pendant 2 minutes après leur création, une exception toujours appliquée par
  Chrome à la mi-2026 sans date de retrait annoncée. Un `SameSite=Lax` explicite
  n'obtient jamais l'exception, une raison de plus de régler l'attribut
  vous-même.
* **`SameSite` est à portée de site, pas d'origine.** Les sous-domaines frères
  comptent comme same-site, donc l'attribut n'offre aucune protection contre un
  sous-domaine compromis. Et `http://` face à `https://` sur le même hôte ne
  compte comme cross-site que là où le same-site avec schéma est livré (Chrome,
  pas Safari, Firefox derrière un flag).
* **`Domain` élargit l'exposition.** `Domain=example.com` envoie le cookie à
  chaque sous-domaine et laisse chaque sous-domaine l'écraser. Omettez-le pour
  que le cookie reste réservé à l'hôte ; `__Host-` impose exactement cela.
* **Les préfixes ne sont qu'un durcissement côté client.** Un navigateur qui ne
  connaît pas un préfixe stocke le cookie sans aucune vérification, et
  [PortSwigger a documenté des cas limites d'analyse](https://portswigger.net/research/cookie-chaos-how-to-bypass-host-and-secure-cookie-prefixes)
  qui contournent les vérifications dans les navigateurs qui les connaissent. Ils
  durcissent une conception, ils ne remplacent pas les contrôles de session côté
  serveur.
* **`Strict` abandonne les sessions sur les liens entrants.** Un cookie de
  session `SameSite=Strict` n'est pas envoyé quand l'utilisateur arrive depuis un
  autre site, si bien que les visiteurs qui suivent un lien depuis un e-mail ou
  des résultats de recherche paraissent déconnectés jusqu'à ce qu'ils naviguent
  de nouveau.

## Comment le mettre en place [#comment-le-mettre-en-place]

1. Nommez le cookie de session avec le préfixe `__Host-` et posez-y `Secure`,
   `HttpOnly` et `SameSite`, `Strict` si vos utilisateurs n'entrent jamais dans
   l'application par des liens cross-site, sinon `Lax`.
2. Supprimez l'attribut `Domain` et mettez `Path=/` ; `__Host-` exige les deux,
   et les cookies réservés à l'hôte sont tout l'intérêt.
3. Omettez `Expires` et `Max-Age` pour que le cookie de session soit non
   persistant et meure avec la session du navigateur.
4. Testez les parcours d'entrée cross-site (liens depuis un e-mail, redirections
   OAuth, tout contenu intégré) avant de vous arrêter sur `Strict`, et donnez aux
   cookies d'intégration réellement cross-site `SameSite=None; Secure;
   Partitioned` plutôt que d'assouplir le cookie de session.
5. Vérifiez les attributs `Set-Cookie` déployés, ainsi que le reste de vos
   headers de réponse, avec le
   [scanner de headers de sécurité](/tools/security-headers).

## Recommandation [#recommandation]

Posez chaque cookie de session avec le préfixe `__Host-` plus `Secure`,
`HttpOnly` et une valeur `SameSite` explicite :

```http
Set-Cookie: __Host-session=<value>; Secure; HttpOnly; SameSite=Lax; Path=/
```

Cela suit le
[cheat sheet OWASP sur la gestion des sessions](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html) :
`Secure` et `HttpOnly` toujours, `SameSite=Strict` de préférence ou `Lax` là où
les liens d'entrée cross-site doivent conserver la session, jamais le défaut du
navigateur, et le préfixe `__Host-` sur les identifiants de session. Aucun
attribut `Domain`, un `Path` restrictif, et pas d'`Expires` ni de `Max-Age` pour
que le cookie ne persiste pas sur le disque.

## Prise en charge par les navigateurs [#prise-en-charge-par-les-navigateurs]

Les attributs de base sont universels : `Secure`, `HttpOnly`, les trois valeurs
`SameSite` et les préfixes `__Secure-` et `__Host-` fonctionnent dans tous les
navigateurs actuels. Les différences portent sur les défauts et les attributs
plus récents. Chrome et Edge traitent un cookie sans `SameSite` comme `Lax`
(moins l'exception de 2 minutes sur les POST ci-dessus) ; Firefox n'a ce défaut
que derrière un flag ; Safari ne l'applique jamais, si bien qu'un cookie sans
attribut s'y comporte comme `None`. La règle selon laquelle `SameSite=None` exige
`Secure` est appliquée par Chrome, Edge et le Firefox actuel, mais pas par
Safari. Les préfixes `__Http-` et `__Host-Http-` sont récents dans Chrome et
Firefox, sans prise en charge par Safari, et `Partitioned` est Baseline largement
disponible dans Chrome, Firefox et Safari. Le paysage des cookies tiers s'est
stabilisé en 2025 : Chrome
[a conservé les cookies tiers](https://privacysandbox.google.com/blog/update-on-plans-for-privacy-sandbox-technologies)
tout en gardant CHIPS, Safari les bloque avec Intelligent Tracking Prevention, et
Firefox les partitionne avec Total Cookie Protection.

## FAQ [#faq]

### SameSite remplace-t-il les jetons CSRF ? [#samesite-remplace-t-il-les-jetons-csrf-]

Non. `SameSite` réduit le CSRF en défense en profondeur mais reste à portée de
site et dépendant du navigateur ; gardez vos jetons CSRF.
[SameSite contre les tokens CSRF](/fr/blog/samesite-vs-csrf-tokens) détaille les
failles et les contournements documentés.

### SameSite Strict ou Lax ? [#samesite-strict-ou-lax-]

`Strict` n'envoie le cookie que sur les requêtes same-site, donc il abandonne la
session quand un utilisateur arrive par un lien cross-site entrant, et celui-ci
paraît déconnecté jusqu'à ce qu'il navigue de nouveau. `Lax` conserve les
navigations GET de premier niveau, donc les sessions survivent aux liens depuis un
e-mail ou une recherche. OWASP préfère `Strict` ; `Lax` reste acceptable.

### Pourquoi mon cookie SameSite=None n'est-il pas posé ? [#pourquoi-mon-cookie-samesitenone-nest-il-pas-posé-]

Il lui manque l'attribut `Secure`. Un cookie posé avec `SameSite=None` est rejeté
d'emblée sauf si `Secure` est aussi présent, donc Chrome, Edge et le Firefox actuel
refusent silencieusement de le stocker. Ajoutez `Secure`, et pour l'état d'un
widget intégré, préférez `SameSite=None; Secure; Partitioned` afin que le cookie ne
devienne pas un identifiant cross-site.

### HttpOnly empêche-t-il le CSRF ? [#httponly-empêche-t-il-le-csrf-]

Non. `HttpOnly` cache le cookie à `document.cookie` et à l'API Cookie Store, ce qui
empêche un script de lire et d'exfiltrer la valeur. Il n'empêche pas le navigateur
d'attacher le cookie aux requêtes cross-site, ce dont abuse justement le CSRF.
Utilisez `SameSite` et des jetons CSRF pour cela.

## Voir aussi [#voir-aussi]

* [Strict-Transport-Security](/fr/docs/web-security/security-headers/strict-transport-security),
  le header qui rend l'attribut `Secure` étanche en supprimant entièrement le
  saut HTTP en clair
* [Vue d'ensemble des headers de sécurité](/fr/docs/web-security/security-headers)
* [Cache-Control](/fr/docs/web-security/security-headers/cache-control) pour
  garder hors des caches partagés les réponses qui portent la session
* [Scanner de headers de sécurité](/tools/security-headers) pour vérifier
  vos attributs de cookie et le reste de vos headers déployés

## Sources [#sources]

* [draft-ietf-httpbis-rfc6265bis, Cookies, mécanisme de gestion d'état HTTP](https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html)
* [MDN, Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie)
* [OWASP, cheat sheet de gestion des sessions](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)
* [MDN, cookies à état partitionné indépendant (CHIPS)](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies/Partitioned_cookies)
* [Source Chromium, cookie\_constants.h (l'exception Lax+POST)](https://github.com/chromium/chromium/blob/main/net/cookies/cookie_constants.h)
