no-cache vs no-store, quelle directive Cache-Control garde les données privées
CentralCSP Team ·
Dernière mise à jour:
Les noms sonnent comme des synonymes, et c'est le piège. no-cache ne veut pas dire
« ne pas mettre en cache ». Il veut dire « stocke-le, mais vérifie auprès du serveur
avant de le réutiliser ». La directive qui garde réellement une réponse hors des
caches est no-store, et pour une page comportant des données personnelles cette
différence change tout.
Si vous avez une réponse qui transporte un identifiant de session ou des données
personnelles, la directive Cache-Control
que vous voulez est no-store. no-cache laisse toujours le navigateur et les caches
partagés garder les octets, il ne fait que forcer une revalidation avant réutilisation.
Pour la confidentialité, stocké-mais-revalidé ne suffit pas ; vous voulez jamais-stocké.
no-cache vs no-store, ce que chaque directive dit à un cache
Les deux directives viennent du RFC 9111, la spécification de la mise en cache HTTP, qui les définit précisément. La confusion est entièrement dans les noms, alors commençons par ce que chacune ordonne réellement à un cache de faire.
Il y a deux niveaux de cache à garder en tête. Un cache privé est le navigateur de
l'utilisateur. Un cache partagé est un proxy d'entreprise, un CDN, ou un reverse proxy
qui stocke une réponse et la réutilise pour de nombreux utilisateurs. HTTP est conçu
pour mettre en cache de façon agressive, si bien qu'une réponse sans aucun header
Cache-Control peut quand même être stockée et réutilisée via la mise en cache
heuristique (RFC 9111 section 4.2.2, avec une durée de vie heuristique typiquement
autour de 10 % de l'ancienneté Last-Modified de la ressource). Et la spécification
est explicite sur le fait que Set-Cookie n'empêche pas la mise en cache : une réponse
cachable portant un header Set-Cookie peut être, et est souvent, utilisée pour
satisfaire d'autres requêtes. Si vous voulez qu'une réponse reste hors des caches,
vous devez le dire.
no-cache stocke la réponse, puis revalide
no-cache (RFC 9111 section 5.2.2.4) signifie qu'un cache peut stocker la réponse
mais ne doit pas la réutiliser sans une revalidation réussie auprès du serveur
d'origine. Le stockage est permis, pas imposé, donc la copie peut se trouver sur le
disque ou en mémoire. À la requête suivante, le cache demande au serveur « ma copie
est-elle encore bonne ? » et ne la réutilise que sur un 304. MDN le dit textuellement :
« no-cache ne veut pas dire ne pas mettre en cache ».
Cache-Control: no-cachePour la confidentialité cela ne fait rien. La réponse peut être posée dans le cache, et
quiconque y a accès, le proxy partagé ou le disque de l'utilisateur sur une machine
partagée, peut lire la copie stockée. La revalidation contrôle la fraîcheur, pas qui
peut voir les octets. Elle ne contraint pas non plus votre edge. Cloudflare respecte le
Cache-Control de l'origine par défaut, mais les cache rules et les réglages de TTL
edge peuvent le compléter ou le remplacer, donc no-cache à l'origine ne contraint pas
une couche CDN mal configurée.
no-store garde la réponse hors de tout cache
no-store (RFC 9111 section 5.2.2.5) est la directive stricte. Un cache « NE DOIT PAS
stocker la moindre partie de la requête immédiate ou de la réponse et NE DOIT PAS
utiliser la réponse pour satisfaire une autre requête ». Cela s'applique aussi bien aux
caches privés qu'aux caches partagés.
Cache-Control: no-storeC'est la directive pour toute réponse contenant un identifiant de session ou des
données personnelles, et c'est ce que la cheat sheet Session Management de l'OWASP
prescrit pour les réponses transportant des identifiants de session. Avec no-store,
les directives supplémentaires et le header Expires que les gens empilent sont
généralement inutiles pour les navigateurs modernes. L'incantation héritée
private, no-cache, no-store, max-age=0, must-revalidate est, selon l'exemple même de
MDN, équivalente à un simple no-store, parce que la directive la plus restrictive
l'emporte.
Une réserve honnête de la spécification elle-même : le RFC 9111 avertit que no-store
« n'est pas un mécanisme fiable ou suffisant pour garantir la confidentialité », parce
que des caches malveillants ou non conformes pourraient ne pas l'honorer. C'est une
instruction adressée aux caches bien élevés, pas du chiffrement. Utilisez-la, et ne la
traitez pas comme le seul contrôle.
private ne stoppe que les caches partagés
private (RFC 9111 section 5.2.2.7) dit que les caches partagés ne doivent pas stocker
la réponse, mais le cache propre du navigateur le peut encore. Elle cadre une réponse
personnalisée à un seul utilisateur en la gardant hors des proxies et CDN, ce qui est
utile, mais ce n'est pas un contrôle de confidentialité contre le stockage local des
octets. private seule laisse toujours la réponse sur le disque de l'utilisateur.
Cache-Control: private, no-cacheCette combinaison, private, no-cache, est un compromis raisonnable pour une page
personnalisée qu'on peut mettre en cache dans le navigateur mais qui doit revalider et
ne jamais toucher un cache partagé. Ce n'est pas le réglage pour un token de session ;
celui-là reste no-store.
Se tromper sur ce niveau a un historique. Les attaques de web cache deception
fonctionnent précisément quand du contenu dynamique par utilisateur est stockable par un
cache partagé, et la défense est no-store ou private sur les réponses dynamiques.
Dans l'incident Steam de Noël 2015, une couche de cache a servi des pages du store
authentifiées aux mauvais utilisateurs, et des pages appartenant à environ
34 000 utilisateurs, certaines incluant des adresses de facturation et des chiffres
partiels de carte bancaire, ont été montrées à d'autres clients.
no-cache vs no-store vs private, côte à côte
| Directive | Peut être stockée ? | Réutilisée sans demander au serveur ? | Quels caches |
|---|---|---|---|
no-store | Non | Jamais stockée | Privé et partagé |
no-cache | Autorisé (disque ou mémoire) | Non, revalide d'abord | Privé et partagé |
private | Navigateur seulement | Oui, tant que fraîche | Privé seulement, partagé interdit |
Le back/forward cache joue selon d'autres règles
Le back/forward cache (bfcache) n'est pas un cache HTTP. Il garde un instantané vivant
d'une page pour qu'un retour arrière soit instantané, et parce qu'il restaure
l'instantané sans revalider, Cache-Control ne le gouverne que partiellement. MDN note
que même no-cache ne garantit pas la revalidation lors des navigations dans
l'historique.
Chrome restaure désormais même les pages no-store depuis le bfcache (le déploiement à
tous les utilisateurs s'est achevé en 2025), avec des atténuations : la page n'est pas
restaurée si elle a utilisé WebSocket, WebTransport ou WebRTC, l'entrée est évincée
quand les cookies ou d'autres méthodes d'autorisation changent ou quand une requête de
sous-ressource revient avec no-store, et l'entrée est plafonnée à 3 minutes au lieu
des 10 habituelles. La documentation de Chrome note que d'autres navigateurs peuvent
encore bloquer le bfcache quand Cache-Control: no-store est présent, donc ne supposez
pas un comportement uniforme entre les moteurs.
La conséquence de sécurité est concrète : un utilisateur qui se déconnecte et clique sur
le bouton retour peut se voir présenter à nouveau la page authentifiée. La déconnexion
doit donc réellement invalider la session, en changeant ou effaçant le
cookie de session côté
serveur, pas seulement naviguer ailleurs. Parce que l'éviction du bfcache est liée à un
changement de cookie, effacer le cookie de session est ce qui rend la page restaurée
sûre, pas la directive de cache. L'OWASP recommande en plus d'effacer l'état client à
la déconnexion avec un header Clear-Site-Data.
Clear-Site-Data: "cache", "cookies", "storage"Les directives sont des chaînes entre guillemets et le header ne fonctionne qu'en HTTPS.
Le support de "cookies" et "storage" est large ; celui de "cache" est inégal selon
les moteurs, alors traitez-le comme une couche supplémentaire plutôt que comme le
mécanisme. Pour les navigateurs où une restauration bfcache reste possible, web.dev
suggère une vérification ceinture et bretelles : écouter l'event pageshow, vérifier
qu'un cookie propre au site est toujours présent, et forcer un rechargement s'il a
disparu.
L'erreur se produit aussi en sens inverse. N'utilisez pas no-store comme bloqueur de
bfcache sur des pages ordinaires. La recommandation de web.dev est de réserver
no-store aux pages où toute mise en cache est inappropriée, et d'utiliser no-cache
ou max-age=0 ailleurs, puisque ceux-ci n'affectent pas l'éligibilité d'une page au
bfcache. Un no-store généralisé tue la navigation arrière/avant instantanée sans
aucun gain de sécurité.
Recommandation
Réglez la mise en cache par réponse, pas à l'échelle du site. Envoyez
Cache-Control: no-store sur toute réponse qui transporte un identifiant de session ou
des données sensibles, connexion, compte, paiement, tout ce qui est personnalisé.
Gardez la mise en cache longue durée là où elle a sa place, sur les assets statiques à
empreinte, avec max-age=31536000, immutable.
Cache-Control: max-age=31536000, immutableUne note sur immutable : Firefox et Safari l'honorent, Chrome et Edge l'ignorent.
L'ignorer est sans conséquence, le max-age s'applique toujours, donc le motif reste
correct partout.
Et associez no-store à une vraie déconnexion : invalidez la session côté serveur,
effacez le cookie de session, et envoyez Clear-Site-Data pour qu'une page restaurée du
bfcache ne puisse pas montrer de contenu authentifié. Pour trouver les réponses qui
posent ou exigent un cookie de session mais ne portent aucune directive les gardant hors
des caches partagés, le scanner de headers de sécurité gratuit
de CentralCSP les signale pour que vous ajoutiez no-store avant que cela ne devienne une fuite.
FAQ
Pourquoi Cache-Control no-cache ne fonctionne-t-il pas ?
Il fonctionne, en général, exactement comme spécifié. no-cache permet le stockage et
permet la réutilisation après une revalidation 304, donc des copies en cache sur le
disque et des rechargements rapides sont attendus. Les restaurations via le bouton
retour peuvent le contourner entièrement, parce que le bfcache restaure un instantané
sans revalider. Et une couche CDN avec ses propres cache rules peut passer outre les
headers de l'origine. Si le comportement que vous vouliez était « jamais stocké », la
directive que vous vouliez était no-store.
no-cache empêche-t-il la mise en cache ?
Non. Il empêche la réutilisation sans revalidation, pas le stockage. MDN le dit
directement : si le sens de « ne pas mettre en cache » que vous voulez est en réalité
« ne pas stocker », alors no-store est la directive à utiliser.
Quelle directive Cache-Control utiliser pour des données sensibles ?
Cache-Control: no-store sur chaque réponse transportant un identifiant de session ou
des données personnelles. C'est la recommandation de l'OWASP, et les directives
supplémentaires ainsi que le header Expires sont généralement inutiles pour les
navigateurs modernes.
Le bouton retour peut-il afficher une page envoyée avec no-store ?
Oui, dans Chrome. no-store garde la réponse hors des caches HTTP, mais Chrome
restaure même les pages no-store depuis le bfcache, avec éviction lors des changements
de cookies et un plafond de 3 minutes. Le bouton retour peut donc encore afficher la
page, sauf si la déconnexion a changé ou effacé le cookie de session. Associez
l'invalidation de session côté serveur à Clear-Site-Data, et éventuellement une
vérification de cookie sur pageshow qui recharge la page.
Dois-je utiliser no-store sur toutes les pages ?
Non. Réservez no-store aux réponses où toute mise en cache est inappropriée, tout ce
qui transporte un identifiant de session ou des données personnelles. Sur des pages
ordinaires il force un téléchargement complet à chaque requête et peut bloquer les
restaurations du back/forward cache dans certains moteurs, donc la navigation devient
plus lente sans aucun gain de sécurité. Utilisez no-cache ou max-age=0 à la place.
À lire ensuite
- Comment améliorer votre note de headers de sécurité
- SameSite contre les tokens CSRF, qui protège vos sessions
- Référence Cache-Control
- Référence cookie security
Sources
- RFC 9111, HTTP Caching
- MDN, Cache-Control
- MDN, guide de la mise en cache HTTP
- Chrome, bfcache and Cache-Control no-store
- web.dev, Back/forward cache
- OWASP, Session Management cheat sheet
- OWASP WSTG, Testing for Browser Cache Weaknesses
- MDN, Clear-Site-Data
- PortSwigger, Web cache deception
- Cloudflare, Cache-Control at the edge