Durch Partitionierung des Caches für mehr Sicherheit und Datenschutz sorgen

Eiji Kitamura
Eiji Kitamura

Im Allgemeinen kann durch das Caching die Leistung verbessert werden, da Daten gespeichert werden, sodass zukünftige Anfragen für dieselben Daten schneller verarbeitet werden. Beispielsweise kann eine im Cache gespeicherte Ressource aus dem Netzwerk einen Umlauf zum Server vermeiden. Bei einem im Cache gespeicherten Berechnungsergebnis kann die Zeit für die gleiche Berechnung fehlen.

In Chrome wird der Cache-Mechanismus auf verschiedene Arten verwendet. Der HTTP-Cache ist ein Beispiel dafür.

So funktioniert der HTTP-Cache von Chrome derzeit

Ab Version 85 speichert Chrome aus dem Netzwerk abgerufene Ressourcen im Cache, wobei ihre jeweiligen Ressourcen-URLs als Cache-Schlüssel verwendet werden. Ein Cache-Schlüssel wird verwendet, um eine im Cache gespeicherte Ressource zu identifizieren.

Das folgende Beispiel zeigt, wie ein einzelnes Bild in drei verschiedenen Kontexten im Cache gespeichert und verarbeitet wird:

Cache-Schlüssel: https://x.example/doge.png
Cache-Schlüssel: { https://x.example/doge.png }

Ein Nutzer besucht eine Seite (https://a.example), über die ein Bild angefordert wird (https://x.example/doge.png). Das Bild wird vom Netzwerk angefordert und mit https://x.example/doge.png als Schlüssel im Cache gespeichert.

Cache-Schlüssel: https://x.example/doge.png
Cache-Schlüssel: { https://x.example/doge.png }

Derselbe Nutzer besucht eine andere Seite (https://b.example), die dasselbe Bild (https://x.example/doge.png) anfordert. Der Browser prüft seinen HTTP-Cache, um festzustellen, ob diese Ressource bereits im Cache gespeichert ist. Dabei wird die Bild-URL als Schlüssel verwendet. Der Browser findet eine Übereinstimmung in seinem Cache und verwendet daher die im Cache gespeicherte Version der Ressource.

Cache-Schlüssel: https://x.example/doge.png
Cache-Schlüssel: { https://x.example/doge.png }

Dabei spielt es keine Rolle, ob das Bild in einem iFrame geladen wird. Wenn der Nutzer eine andere Website (https://c.example) mit einem iFrame (https://d.example) besucht und der iFrame dasselbe Bild anfordert (https://x.example/doge.png), kann der Browser das Bild trotzdem aus dem Cache laden, da der Cache-Schlüssel auf allen Seiten identisch ist.

Dieser Mechanismus funktioniert seit Langem in puncto Leistung gut. Die Zeit, die eine Website zum Antworten auf HTTP-Anfragen benötigt, kann jedoch zeigen, dass der Browser in der Vergangenheit auf dieselbe Ressource zugegriffen hat. Dadurch wird der Browser vor Sicherheits- und Datenschutzangriffen wie den folgenden geöffnet:

  • Erkennen, ob ein Nutzer eine bestimmte Website besucht hat: Ein Angreifer kann den Browserverlauf eines Nutzers erkennen, indem er prüft, ob der Cache eine Ressource enthält, die möglicherweise für eine bestimmte Website oder Kohorte von Websites spezifisch ist.
  • Cross-Site Search-Angriff: Ein Angreifer kann erkennen, ob ein beliebiger String in den Suchergebnissen des Nutzers enthalten ist. Dazu wird geprüft, ob sich ein Bild ohne Suchergebnisse, das von einer bestimmten Website verwendet wird, im Cache des Browsers befindet.
  • Websiteübergreifendes Tracking: Im Cache können Cookie-ähnliche IDs für websiteübergreifendes Tracking gespeichert werden.

Um diese Risiken zu minimieren, partitioniert Chrome seinen HTTP-Cache ab Chrome 86.

Wie wirkt sich die Cache-Partitionierung auf den HTTP-Cache von Chrome aus?

Bei der Cache-Partitionierung werden im Cache gespeicherte Ressourcen zusätzlich zur Ressourcen-URL mit einem neuen „Netzwerkisolierungsschlüssel“ verschlüsselt. Der Netzwerkisolierungsschlüssel besteht aus der Website der obersten Ebene und der Website des aktuellen Frames.

Sehen Sie sich das vorherige Beispiel noch einmal an, um zu sehen, wie die Cache-Partitionierung in verschiedenen Kontexten funktioniert:

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://a.example, https://a.example, https://x.example/doge.png }

Ein Nutzer besucht eine Seite (https://a.example), die ein Bild anfordert (https://x.example/doge.png). In diesem Fall wird das Bild vom Netzwerk angefordert und mit einem Tupel im Cache gespeichert, das aus https://a.example (Website der obersten Ebene), https://a.example (Website des aktuellen Frames) und https://x.example/doge.png (Ressourcen-URL) als Schlüssel besteht. Wenn die Ressourcenanfrage vom übergeordneten Frame stammt, sind die Website der obersten Ebene und die Website des aktuellen Frames im Netzwerkisolierungsschlüssel identisch.

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://b.example, https://b.example, https://x.example/doge.png }

Derselbe Nutzer besucht eine andere Seite (https://b.example), die dasselbe Bild (https://x.example/doge.png) anfordert. Obwohl dasselbe Bild im vorherigen Beispiel geladen wurde, ist es kein Cache-Treffer, da der Schlüssel nicht übereinstimmt.

Das Bild wird vom Netzwerk angefordert und mit einem Tupel aus https://b.example, https://b.example und https://x.example/doge.png als Schlüssel im Cache gespeichert.

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://a.example, https://a.example, https://x.example/doge.png }

Der Nutzer kehrt jetzt zu https://a.example zurück, aber dieses Mal ist das Bild (https://x.example/doge.png) in einen iFrame eingebettet. In diesem Fall ist der Schlüssel ein Tupel, das https://a.example, https://a.example und https://x.example/doge.png enthält, und es tritt ein Cache-Treffer auf. Wenn die Top-Level-Website und der iFrame dieselbe Website sind, kann die mit dem Frame der obersten Ebene im Cache gespeicherte Ressource verwendet werden.

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://a.example, https://c.example, https://x.example/doge.png }

Der Nutzer ist wieder bei https://a.example, aber dieses Mal wird das Bild in einem iFrame von https://c.example gehostet.

In diesem Fall wird das Image aus dem Netzwerk heruntergeladen, da sich keine Ressource im Cache befindet, die dem Schlüssel aus https://a.example, https://c.example und https://x.example/doge.png entspricht.

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://a.example, https://c.example, https://x.example/doge.png }

Was passiert, wenn die Domain eine Subdomain oder eine Portnummer enthält? Der Nutzer ruft https://subdomain.a.example auf, wo er einen iFrame (https://c.example:8080) einbettet, der das Bild anfordert.

Da der Schlüssel auf der Grundlage von "scheme://eTLD+1" erstellt wird, werden Subdomains und Portnummern ignoriert. Daher tritt ein Cache-Treffer auf.

Cache-Schlüssel { https://a.example, https://a.example, https://x.example/doge.png}
Cache-Schlüssel: { https://a.example, https://c.example, https://x.example/doge.png }

Was passiert, wenn der iFrame mehrfach verschachtelt ist? Der Nutzer ruft https://a.example auf. Damit wird ein iFrame (https://b.example) eingebettet, in den ein weiterer iFrame (https://c.example) eingebettet ist, der schließlich das Bild anfordert.

Da der Schlüssel aus dem oberen Frame (https://a.example) und dem unmittelbaren Frame, der die Ressource (https://c.example) lädt, entnommen wird, tritt ein Cache-Treffer auf.

Häufig gestellte Fragen

Ist sie in Chrome bereits aktiviert? Wie kann ich das prüfen?

Die Funktion wird Ende 2020 eingeführt. So prüfen Sie, ob Ihre Chrome-Instanz dies bereits unterstützt:

  1. Öffnen Sie chrome://net-export/ und klicken Sie auf Start Logging to Disk (Protokollierung auf Laufwerk starten).
  2. Geben Sie an, wo die Protokolldatei auf dem Computer gespeichert werden soll.
  3. Surfen Sie kurz mit Chrome im Web.
  4. Kehren Sie zu chrome://net-export/ zurück und klicken Sie auf Protokoll beenden.
  5. Öffnen Sie https://netlog-viewer.appspot.com/#import.
  6. Klicken Sie auf Datei auswählen und übergeben Sie die gespeicherte Protokolldatei.

Sie sehen die Ausgabe der Protokolldatei.

Suchen Sie auf derselben Seite nach SplitCacheByNetworkIsolationKey. Wenn darauf Experiment_[****] folgt, ist die HTTP-Cache-Partitionierung in Chrome aktiviert. Darauf folgt Control_[****] oder Default_[****], ist es nicht aktiviert.

Wie kann ich die HTTP-Cache-Partitionierung in Chrome testen?

Um die HTTP-Cache-Partitionierung in Chrome zu testen, müssen Sie Chrome mit einem Befehlszeilen-Flag starten: --enable-features=SplitCacheByNetworkIsolationKey. Folgen Sie der Anleitung unter Chromium mit Flags ausführen, um zu erfahren, wie Sie Chrome mit einem Befehlszeilen-Flag auf Ihrer Plattform starten.

Muss ich als Webentwickler auf diese Änderung reagieren?

Diese Änderung ist keine funktionsgefährdende Änderung, kann aber bei einigen Webdiensten Leistungsabwägungen nach sich ziehen.

Wenn beispielsweise große Mengen an hoch im Cache speicherbaren Ressourcen über viele Websites hinweg bereitgestellt werden (z. B. Schriftarten und beliebte Skripts), kann sich der Traffic erhöhen. Außerdem sind Personen, die solche Dienste in Anspruch nehmen, möglicherweise stärker darauf angewiesen.

Es gibt einen Vorschlag, gemeinsam genutzte Bibliotheken auf datenschutzfreundliche Weise zu aktivieren: Web Shared Libraries (Präsentationsvideo), wird aber noch geprüft.

Welche Auswirkungen hat diese Verhaltensänderung?

Die Cache-Fehlerrate insgesamt steigt um etwa 3,6%, die Änderungen am FCP (First Contentful Paint) sind gering (ca. 0,3%) und der Gesamtanteil der aus dem Netzwerk geladenen Byte steigt um etwa 4%. Weitere Informationen zu den Auswirkungen auf die Leistung finden Sie in der Erläuterung zur HTTP-Cache-Partitionierung.

Ist das standardisiert? Verhalten sich andere Browser anders?

„HTTP-Cache-Partitionen“ sind in der Abrufspezifikation standardisiert, wobei sich Browser jedoch anders verhalten:

  • Chrome: Verwendet Top-Level-schema://eTLD+1 und Frame-Schema://eTLD+1
  • Safari: verwendet die eTLD+1 der obersten Ebene
  • Firefox: Planen der Implementierung mit dem Schema „top-level“ „schema://eTLD+1“ und erwägen, einen zweiten Schlüssel wie Chrome einzubinden

Wie werden Abrufe von Workern behandelt?

Dedizierte Worker verwenden denselben Schlüssel wie ihren aktuellen Frame. Service Worker und freigegebene Worker sind komplizierter, da sie von mehreren übergeordneten Standorten gemeinsam genutzt werden können. Die Lösung wird derzeit diskutiert.

Ressourcen