Renforcement de la sécurité et de la confidentialité grâce au partitionnement du cache

Eiji Kitamura
Eiji Kitamura

En général, la mise en cache peut améliorer les performances en stockant des données afin que les requêtes ultérieures portant sur les mêmes données soient traitées plus rapidement. Par exemple, une ressource mise en cache depuis le réseau peut éviter un aller-retour jusqu'au serveur. Un résultat de calcul mis en cache peut omettre le temps d'effectuer le même calcul.

Dans Chrome, le mécanisme de mise en cache est utilisé de différentes manières. Le cache HTTP en est un exemple.

Fonctionnement actuel du cache HTTP de Chrome

Depuis la version 85, Chrome met en cache les ressources récupérées sur le réseau en utilisant les URL de ressources respectives comme clé de cache. (Une clé de cache permet d'identifier une ressource mise en cache.)

L'exemple suivant montre comment une seule image est mise en cache et traitée dans trois contextes différents:

Clé du cache: https://x.example/doge.png
Clé de cache: { https://x.example/doge.png }

Un utilisateur visite une page (https://a.example) qui demande une image (https://x.example/doge.png). L'image est demandée au réseau et mise en cache en utilisant la clé https://x.example/doge.png.

Clé du cache: https://x.example/doge.png
Clé de cache: { https://x.example/doge.png }

Le même utilisateur visite une autre page (https://b.example), qui demande la même image (https://x.example/doge.png). Le navigateur vérifie son cache HTTP pour voir si cette ressource est déjà mise en cache en utilisant l'URL de l'image comme clé. Le navigateur trouve une correspondance dans son cache. Il utilise donc la version mise en cache de la ressource.

Clé du cache: https://x.example/doge.png
Clé de cache: { https://x.example/doge.png }

Peu importe que l'image soit chargée depuis un iFrame. Si l'utilisateur consulte un autre site Web (https://c.example) avec un iFrame (https://d.example) et que l'iFrame demande la même image (https://x.example/doge.png), le navigateur peut quand même charger l'image à partir de son cache, car la clé de cache est identique sur toutes les pages.

Ce mécanisme fonctionne bien du point de vue des performances depuis longtemps. Toutefois, le temps nécessaire à un site Web pour répondre à des requêtes HTTP peut révéler que le navigateur a accédé à la même ressource par le passé, ce qui l'ouvre à des attaques de sécurité et de confidentialité telles que les suivantes:

  • Détecter si un utilisateur a visité un site spécifique: un adversaire peut détecter l'historique de navigation d'un utilisateur en vérifiant si le cache contient une ressource susceptible d'être spécifique à un site particulier ou à une cohorte de sites.
  • Attaque par recherche intersites : un pirate informatique peut détecter si une chaîne arbitraire figure dans les résultats de recherche de l'utilisateur en vérifiant si une image indiquant qu'un site Web donné ne renvoie aucun résultat de recherche se trouve dans le cache du navigateur.
  • Suivi intersites: le cache peut être utilisé pour stocker des identifiants de type cookie en tant que mécanisme de suivi intersites.

Pour atténuer ces risques, Chrome partitionnera son cache HTTP à partir de Chrome 86.

Quel est l'impact du partitionnement du cache sur le cache HTTP de Chrome ?

Avec le partitionnement du cache, les ressources mises en cache sont associées à une nouvelle "clé d'isolation réseau" en plus de l'URL de la ressource. La clé d'isolation réseau se compose du site de premier niveau et du site du frame actuel.

Examinez à nouveau l'exemple précédent pour voir comment le partitionnement du cache fonctionne dans différents contextes:

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://a.example, https://a.example, https://x.example/doge.png }

Un utilisateur visite une page (https://a.example) qui demande une image (https://x.example/doge.png). Dans ce cas, l'image est demandée au réseau et mise en cache à l'aide d'un tuple composé de https://a.example (site de premier niveau), https://a.example (site du frame actuel) et https://x.example/doge.png (URL de la ressource) comme clé. Notez que lorsque la demande de ressources provient du frame de premier niveau, le site de premier niveau et le site du frame actuel dans la clé d'isolation réseau sont identiques.

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://b.example, https://b.example, https://x.example/doge.png }

Le même utilisateur visite une autre page (https://b.example) qui demande la même image (https://x.example/doge.png). Même si la même image a été chargée dans l'exemple précédent, comme la clé ne correspond pas, il ne s'agit pas d'un succès de cache.

L'image est demandée à partir du réseau et mise en cache à l'aide d'un tuple constitué de https://b.example, https://b.example et https://x.example/doge.png comme clé.

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://a.example, https://a.example, https://x.example/doge.png }

L'utilisateur revient maintenant dans https://a.example, mais cette fois, l'image (https://x.example/doge.png) est intégrée dans un iFrame. Dans ce cas, la clé est un tuple contenant https://a.example, https://a.example et https://x.example/doge.png, et un succès de cache se produit. Notez que lorsque le site de premier niveau et l'iFrame correspondent au même site, la ressource mise en cache avec le frame de premier niveau peut être utilisée.

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://a.example, https://c.example, https://x.example/doge.png }

L'utilisateur est de retour à https://a.example, mais cette fois, l'image est hébergée dans un iFrame de https://c.example.

Dans ce cas, l'image est téléchargée à partir du réseau, car aucune ressource du cache ne correspond à la clé composée de https://a.example, https://c.example et https://x.example/doge.png.

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://a.example, https://c.example, https://x.example/doge.png }

Que se passe-t-il si le domaine contient un sous-domaine ou un numéro de port ? L'utilisateur accède à https://subdomain.a.example, qui intègre un iFrame (https://c.example:8080), qui demande l'image.

Étant donné que la clé est créée sur la base de "schéma://eTLD+1", les sous-domaines et les numéros de port sont ignorés. Cela explique pourquoi un succès de cache (hit) se produit.

Clé de cache { https://a.example, https://a.example, https://x.example/doge.png}
Clé de cache: { https://a.example, https://c.example, https://x.example/doge.png }

Que se passe-t-il si l'iFrame est imbriqué plusieurs fois ? L'utilisateur visite https://a.example, qui intègre un iFrame (https://b.example), qui intègre encore un autre iFrame (https://c.example), qui demande finalement l'image.

Étant donné que la clé est extraite du frame supérieur (https://a.example) et du frame immédiat qui charge la ressource (https://c.example), un succès de cache se produit.

Questions fréquentes

Est-elle déjà activée sur mon navigateur Chrome ? Comment vérifier ?

Cette fonctionnalité sera déployée jusqu'à fin 2020. Pour vérifier si votre instance Chrome la prend déjà en charge, procédez comme suit:

  1. Ouvrez chrome://net-export/ et appuyez sur Start Logging to Disk (Démarrer la journalisation sur le disque).
  2. Indiquez l'emplacement où enregistrer le fichier journal sur votre ordinateur.
  3. Parcourez le Web sur Chrome pendant une minute.
  4. Revenez dans chrome://net-export/ et appuyez sur Arrêter la journalisation.
  5. Accédez à https://netlog-viewer.appspot.com/#import.
  6. Appuyez sur Choose File (Sélectionner un fichier) et transmettez le fichier journal que vous avez enregistré.

La sortie du fichier journal s'affiche.

Sur la même page, recherchez SplitCacheByNetworkIsolationKey. S'il est suivi de Experiment_[****], le partitionnement du cache HTTP est activé sur Chrome. S'il est suivi de Control_[****] ou de Default_[****], il n'est pas activé.

Comment tester le partitionnement du cache HTTP dans Chrome ?

Pour tester le partitionnement du cache HTTP sur votre navigateur Chrome, vous devez lancer Chrome avec un indicateur de ligne de commande: --enable-features=SplitCacheByNetworkIsolationKey. Suivez les instructions de la section Exécuter Chromium avec des indicateurs pour découvrir comment lancer Chrome avec un indicateur de ligne de commande sur votre plate-forme.

En tant que développeur Web, dois-je prendre des mesures en réponse à ce changement ?

Il ne s'agit pas d'une modification destructive, mais elle peut imposer des considérations relatives aux performances pour certains services Web.

Par exemple, ceux qui diffusent d'importants volumes de ressources pouvant être mises en cache sur de nombreux sites (comme les polices et les scripts populaires) peuvent constater une augmentation de leur trafic. En outre, ceux qui utilisent ces services peuvent dépendre davantage d'eux.

(Une proposition visant à activer les bibliothèques partagées tout en préservant la confidentialité est disponible, appelée bibliothèques partagées Web (vidéo de présentation), mais elle reste à l'étude.)

Quel est l'impact de ce changement de comportement ?

Le taux global de défaut de cache augmente d'environ 3,6%, les modifications apportées au FCP (First Contentful Paint) sont modestes (~0,3%) et la fraction globale d'octets chargés depuis le réseau augmente d'environ 4%. Pour en savoir plus sur l'impact sur les performances, consultez le guide du partitionnement du cache HTTP.

Est-ce standardisé ? Les autres navigateurs se comportent-ils différemment ?

Les "partitions de cache HTTP" sont normalisées dans la spécification de récupération bien que les navigateurs se comportent différemment:

Comment la récupération des nœuds de calcul est-elle traitée ?

Les nœuds de calcul dédiés utilisent la même clé que leur frame actuel. Les service workers et les workers partagés sont plus compliqués, car ils peuvent être partagés entre plusieurs sites de premier niveau. Une solution à ce problème est en cours de discussion.

Ressources