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-cacheCô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-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 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-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 à 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
| 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 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, immutableUne 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
- 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