Partizionamento della cache per maggiore sicurezza e privacy

Eiji Kitamura
Eiji Kitamura

In generale, la memorizzazione nella cache può migliorare le prestazioni archiviando i dati in modo da gestire più rapidamente le richieste future per gli stessi dati. Ad esempio, una risorsa della rete memorizzata nella cache può evitare un round trip al server. Un risultato computazionale memorizzato nella cache può omettere il tempo necessario per eseguire lo stesso calcolo.

In Chrome il meccanismo della cache viene utilizzato in vari modi, mentre HTTP Cache è un esempio.

Come funziona attualmente la cache HTTP di Chrome

A partire dalla versione 85, Chrome memorizza nella cache le risorse recuperate dalla rete, utilizzando i rispettivi URL delle risorse come chiave cache. (Una chiave cache viene utilizzata per identificare una risorsa memorizzata nella cache.)

L'esempio seguente illustra come una singola immagine viene memorizzata nella cache e trattata in tre contesti diversi:

Chiave cache: https://x.example/doge.png
Chiave cache: { https://x.example/doge.png }

Un utente visita una pagina (https://a.example) che richiede un'immagine (https://x.example/doge.png). L'immagine viene richiesta dalla rete e memorizzata nella cache utilizzando https://x.example/doge.png come chiave.

Chiave cache: https://x.example/doge.png
Chiave cache: { https://x.example/doge.png }

Lo stesso utente visita un'altra pagina (https://b.example) che richiede la stessa immagine (https://x.example/doge.png). Il browser controlla la cache HTTP per verificare se la risorsa è già memorizzata nella cache e utilizza l'URL dell'immagine come chiave. Il browser trova una corrispondenza nella cache, quindi utilizza la versione memorizzata nella cache della risorsa.

Chiave cache: https://x.example/doge.png
Chiave cache: { https://x.example/doge.png }

Non importa se l'immagine viene caricata dall'interno di un iframe. Se l'utente visita un altro sito web (https://c.example) con un iframe (https://d.example) e l'iframe richiede la stessa immagine (https://x.example/doge.png), il browser può comunque caricare l'immagine dalla cache perché la chiave cache è la stessa in tutte le pagine.

Questo meccanismo funziona da molto tempo dal punto di vista delle prestazioni. Tuttavia, il tempo impiegato da un sito web per rispondere alle richieste HTTP può rivelare che il browser ha eseguito l'accesso alla stessa risorsa in passato, il che apre il browser ad attacchi alla sicurezza e alla privacy, come i seguenti:

  • Rilevare se un utente ha visitato un sito specifico. Un utente malintenzionato può rilevare la cronologia di navigazione di un utente controllando se nella cache è presente una risorsa che potrebbe essere specifica per un determinato sito o coorte di siti.
  • Attacco alla ricerca tra siti: un utente malintenzionato può rilevare se nei risultati di ricerca dell'utente è presente una stringa arbitraria controllando se nella cache del browser è presente l 'immagine "nessun risultato di ricerca" utilizzata da un determinato sito web.
  • Monitoraggio tra siti: la cache può essere utilizzata per memorizzare identificatori simili a cookie come meccanismo di monitoraggio tra siti.

Per mitigare questi rischi, Chrome partiziona la cache HTTP a partire da Chrome 86.

In che modo il partizionamento della cache influisce sulla cache HTTP di Chrome?

Con il partizionamento della cache, le risorse memorizzate nella cache verranno assegnate utilizzando una nuova "Chiave di isolamento della rete" oltre all'URL della risorsa. La chiave di isolamento della rete è composta dal sito di primo livello e dal sito del frame corrente.

Osserva di nuovo l'esempio precedente per vedere come funziona il partizionamento della cache in contesti diversi:

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://a.example, https://a.example, https://x.example/doge.png }

Un utente visita una pagina (https://a.example) che richiede un'immagine (https://x.example/doge.png). In questo caso, l'immagine viene richiesta dalla rete e memorizzata nella cache utilizzando una tupla composta da https://a.example (il sito di primo livello), https://a.example (il sito con frame corrente) e https://x.example/doge.png (l'URL della risorsa) come chiave. Tieni presente che quando la richiesta di risorse proviene dal frame di primo livello, il sito di primo livello e il sito del frame corrente nella chiave di isolamento della rete sono gli stessi.

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://b.example, https://b.example, https://x.example/doge.png }

Lo stesso utente visita una pagina diversa (https://b.example) che richiede la stessa immagine (https://x.example/doge.png). Sebbene nell'esempio precedente sia stata caricata la stessa immagine, poiché la chiave non corrisponde, non sarà un successo della cache.

L'immagine viene richiesta dalla rete e memorizzata nella cache utilizzando una tupla composta da https://b.example, https://b.example e https://x.example/doge.png come chiave.

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://a.example, https://a.example, https://x.example/doge.png }

Ora l'utente torna su https://a.example, ma questa volta l'immagine (https://x.example/doge.png) è incorporata in un iframe. In questo caso, la chiave è una tupla contenente https://a.example, https://a.example e https://x.example/doge.png e si verifica un successo della cache. Tieni presente che, quando il sito di primo livello e l'iframe sono lo stesso sito, è possibile utilizzare la risorsa memorizzata nella cache con il frame di primo livello.

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://a.example, https://c.example, https://x.example/doge.png }

L'utente è tornato all'indirizzo https://a.example, ma questa volta l'immagine è ospitata in un iframe di https://c.example.

In questo caso, l'immagine viene scaricata dalla rete perché nella cache non è presente alcuna risorsa corrispondente alla chiave composta da https://a.example, https://c.example e https://x.example/doge.png.

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://a.example, https://c.example, https://x.example/doge.png }

Che cosa succede se il dominio contiene un sottodominio o un numero di porta? L'utente visita https://subdomain.a.example, che incorpora un iframe (https://c.example:8080) che richiede l'immagine.

Poiché la chiave viene creata in base a "scheme://eTLD+1", i sottodomini e i numeri di porta vengono ignorati. Di conseguenza, si verifica un successo della cache.

Chiave cache { https://a.example, https://a.example, https://x.example/doge.png}
Chiave cache: { https://a.example, https://c.example, https://x.example/doge.png }

Cosa succede se l'iframe viene nidificato più volte? L'utente visita https://a.example, che incorpora un iframe (https://b.example), che incorpora un altro iframe (https://c.example), che alla fine richiede l'immagine.

Poiché la chiave viene recuperata dal frame superiore (https://a.example) e dal frame immediato che carica la risorsa (https://c.example), si verifica un hit dalla cache.

Domande frequenti

È già attivo sul mio Chrome? Come faccio a controllare?

La funzionalità verrà implementata alla fine del 2020. Per verificare se l'istanza di Chrome lo supporta già:

  1. Apri chrome://net-export/ e premi Avvia Logging su disco.
  2. Specifica dove salvare il file di log sul computer.
  3. Naviga per un minuto sul web con Chrome.
  4. Torna a chrome://net-export/ e premi Interrompi logging.
  5. Vai a https://netlog-viewer.appspot.com/#import.
  6. Premi Choose File (Scegli file) e trasmetti il file di log che hai salvato.

Verrà visualizzato l'output del file di log.

Nella stessa pagina, trova SplitCacheByNetworkIsolationKey. Se è seguito da Experiment_[****], su Chrome il partizionamento della cache HTTP è attivato. Se è seguito da Control_[****] o Default_[****], non è abilitato.

Come faccio a testare il partizionamento della cache HTTP sul mio Chrome?

Per testare il partizionamento della cache HTTP su Chrome, devi avviare Chrome con un flag della riga di comando: --enable-features=SplitCacheByNetworkIsolationKey. Segui le istruzioni riportate in Eseguire Chromium con i flag per scoprire come avviare Chrome con un flag della riga di comando sulla tua piattaforma.

In qualità di sviluppatore web, devo intraprendere qualche azione in risposta a questo cambiamento?

Non si tratta di una modifica che provoca un errore, ma potrebbe comportare considerazioni sulle prestazioni per alcuni servizi web.

Ad esempio, tra i siti che pubblicano grandi volumi di risorse altamente memorizzabili nella cache su numerosi siti (come i caratteri e gli script più utilizzati) potrebbe verificarsi un aumento del traffico. Inoltre, coloro che usufruiscono di questi servizi potrebbero fare affidamento maggiormente su di essi.

Esiste una proposta per abilitare le librerie condivise in un modo che tutela la privacy, chiamato Librerie condivise sul web (video di presentazione), ma la proposta è ancora in fase di valutazione.

Qual è l'impatto di questo cambiamento del comportamento?

La percentuale complessiva di fallimento della cache aumenta di circa il 3,6%, le modifiche alla metrica FCP (First Contentful Paint) sono modeste (~0,3%) e la frazione complessiva di byte caricati dalla rete aumenta di circa il 4%. Puoi scoprire di più sull'impatto sulle prestazioni nel spiegazione sul partizionamento della cache HTTP.

È standardizzato? Gli altri browser si comportano in modo diverso?

Le "partizioni cache HTTP" sono standardizzate nella specifica di recupero, anche se i browser si comportano in modo diverso:

  • Chrome: utilizza lo schema di primo livello://eTLD+1 e lo schema di frame://eTLD+1.
  • Safari: utilizza eTLD+1 di primo livello
  • Firefox: è in corso l'implementazione con lo schema di primo livello://eTLD+1 e stiamo valutando l'inclusione di una seconda chiave come Chrome.

Come viene trattato il recupero dai worker?

I worker dedicati utilizzano la stessa chiave del frame corrente. I service worker e i worker condivisi sono più complicati poiché possono essere condivisi tra più siti di primo livello. La soluzione è attualmente in fase di discussione.

Risorse