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 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-cache

Pour 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-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 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-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 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

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 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, immutable

Une 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

Sources