Tous les articles

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 qui contient des données personnelles, cette différence change tout.

Pour une réponse qui transporte un identifiant de session ou des données personnelles, la directive Cache-Control à utiliser est no-store. no-cache laisse le navigateur et les caches partagés conserver les octets ; il force seulement 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 tient entièrement aux noms, alors commençons par ce que chacune demande vraiment à un cache.

Deux niveaux de cache sont à 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). La spécification est d'ailleurs 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 servir, et sert souvent, à satisfaire d'autres requêtes. Si vous voulez qu'une réponse reste hors des caches, il faut 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-cache

Côté confidentialité, cela n'apporte rien. La réponse peut se retrouver dans le cache, et quiconque y a accès, que ce soit 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-store

C'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 l'on empile par habitude 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, venue 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, mais n'en faites pas votre 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 réserve à un seul utilisateur une réponse personnalisée en la gardant hors des proxies et des 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-cache

Cette 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 à ce niveau a déjà eu des conséquences. Les attaques de web cache deception fonctionnent précisément quand un cache partagé peut stocker du contenu dynamique propre à un utilisateur, 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 : les pages d'environ 34 000 utilisateurs, dont certaines contenaient des adresses de facturation et des chiffres partiels de carte bancaire, se sont affichées chez d'autres clients.

no-cache vs no-store vs private, côte à côte

DirectivePeut être stockée ?Réutilisée sans demander au serveur ?Quels caches
no-storeNonJamais stockéePrivé et partagé
no-cacheAutorisé (disque ou mémoire)Non, revalide d'abordPrivé et partagé
privateNavigateur seulementOui, tant que fraîchePrivé 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 retomber sur la page authentifiée. La déconnexion doit donc vraiment invalider la session, en changeant ou en effaçant le cookie de session côté serveur, pas se contenter de rediriger ailleurs. Comme l'éviction du bfcache dépend d'un changement de cookie, c'est l'effacement du cookie de session qui rend la page restaurée inoffensive, 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. La prise en charge de "cookies" et "storage" est large ; celle de "cache" est inégale selon les moteurs, alors traitez-le comme une couche supplémentaire, pas comme le mécanisme principal. 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 existe aussi dans l'autre sens. 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, qui 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 dont le nom porte une empreinte, avec max-age=31536000, immutable.

Cache-Control: max-age=31536000, immutable

Une note sur immutable : Firefox et Safari l'honorent, Chrome et Edge l'ignorent. Cet oubli est sans conséquence : le max-age s'applique quand même, donc l'approche reste valable 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é. Le scanner de headers de sécurité gratuit de CentralCSP repère les réponses qui posent ou exigent un cookie de session sans porter la moindre directive les gardant hors des caches partagés, pour que vous ajoutiez no-store avant que cela ne tourne à la 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 normaux. 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 une page ordinaire, 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

Sources