Isolamento dei siti per sviluppatori web

Chrome 67 per computer ha una nuova funzionalità chiamata Isolamento dei siti attiva per impostazione predefinita. Questo articolo spiega che cos'è l'isolamento dei siti, perché è necessario e perché gli sviluppatori web dovrebbero esserne a conoscenza.

Che cos'è l'isolamento dei siti?

Internet è fatto per guardare video di gatti e gestire i portafogli di criptovalute, tra le altre cose, ma non vorresti che fluffycats.example avesse accesso alle tue preziose criptomonete. Fortunatamente, solitamente i siti web non possono accedere ai dati l'uno dell'altro all'interno del browser grazie al principio di origine stessa. Tuttavia, i siti web dannosi potrebbero tentare di aggirare questo criterio per attaccare altri siti web e, a volte, vengono rilevati bug di sicurezza nel codice del browser che applica il criterio della stessa origine. Il team di Chrome si impegna a correggere questi bug il più rapidamente possibile.

L'isolamento dei siti è una funzionalità di sicurezza di Chrome che offre una linea di difesa aggiuntiva per ridurre le probabilità di successo di questi attacchi. Garantisce che le pagine di siti web diversi vengano sempre inserite in processi diversi, ognuno in esecuzione in una sandbox che limita le attività consentite al processo. Inoltre, impedisce al processo di ricevere determinati tipi di dati sensibili da altri siti. Di conseguenza, con l'isolamento dei siti è molto più difficile per un sito web dannoso utilizzare attacchi speculativi lato canale come Spectre per rubare dati da altri siti. Man mano che il team di Chrome completa altre applicazioni, l'isolamento dei siti sarà utile anche quando la pagina di un malintenzionato può violare alcune delle regole nel proprio processo.

L'isolamento dei siti rende più difficile per i siti web non attendibili accedere o rubare informazioni dai tuoi account su altri siti web. Offre protezione aggiuntiva contro vari tipi di bug di sicurezza, come i recenti attacchi al canale laterale Meltdown e Spectre.

Per maggiori dettagli sull'isolamento dei siti, vedi il nostro articolo sul blog sulla sicurezza di Google.

Blocco della lettura tra origini

Anche quando tutte le pagine cross-site vengono inserite in processi separati, le pagine possono comunque richiedere legittimamente alcune risorse secondarie cross-site, come immagini e JavaScript. Una pagina web dannosa potrebbe utilizzare un elemento <img> per caricare un file JSON con dati sensibili, ad esempio il saldo del tuo conto bancario:

<img src="https://your-bank.example/balance.json" />
<!-- Note: the attacker refused to add an `alt` attribute, for extra evil points. -->

Senza l'isolamento dei siti, i contenuti del file JSON arriverebbero nella memoria del processo del visualizzatore, che a quel punto nota che non si tratta di un formato di immagine valido e non la visualizza. Tuttavia, l'utente malintenzionato potrebbe sfruttare una vulnerabilità come Spectre per leggere potenzialmente quel frammento di memoria.

Anziché utilizzare <img>, l'attaccante potrebbe anche utilizzare <script> per eseguire il commit dei dati sensibili nella memoria:

<script src="https://your-bank.example/balance.json"></script>

Il blocco della lettura interorigine (CORB) è una nuova funzionalità di sicurezza che impedisce ai contenuti dibalance.json di entrare nella memoria del processo di rendering in base al tipo MIME.

Vediamo come funziona CORB. Un sito web può richiedere due tipi di risorse a un server:

  1. risorse di dati come documenti HTML, XML o JSON
  2. Risorse multimediali come immagini, JavaScript, CSS o caratteri

Un sito web è in grado di ricevere risorse di dati dalla propria origine o da altre origini con intestazioni CORS permissive come Access-Control-Allow-Origin: *. D'altra parte, le risorse multimediali possono essere incluse da qualsiasi origine, anche senza intestazioni CORS permissive.

CORB impedisce al processo di rendering di ricevere una risorsa di dati cross-origin (ad es. HTML, XML o JSON) se:

  • la risorsa ha un'intestazione X-Content-Type-Options: nosniff
  • CORS non consente esplicitamente l'accesso alla risorsa

Se la risorsa di dati cross-origin non ha l'intestazione X-Content-Type-Options: nosniff impostata, CORB tenta di analizzare il corpo della risposta per determinare se si tratta di HTML, XML o JSON. Questo è necessario perché alcuni server web sono configurati in modo errato e pubblicano immagini come text/html, ad esempio.

Le risorse di dati bloccate dal criterio CORB vengono presentate al processo come vuote, anche se la richiesta viene comunque eseguita in background. Di conseguenza, una pagina web dannosa ha difficoltà a inserire dati cross-site nel suo processo per sottrarli.

Per una sicurezza ottimale e per usufruire di CORB, ti consigliamo quanto segue:

  • Contrassegna le risposte con l'intestazione Content-Type corretta. Ad esempio, le risorse HTML devono essere pubblicate come text/html, le risorse JSON con un tipo MIME JSON e le risorse XML con un tipo MIME XML.
  • Disattivare lo sniffing utilizzando l'intestazione X-Content-Type-Options: nosniff. Senza questa intestazione, Chrome esegue un'analisi rapida dei contenuti per verificare che il tipo sia corretto, ma poiché tende a consentire le risposte per evitare di bloccare elementi come i file JavaScript, è meglio fare la cosa giusta in modo affermativo.

Per ulteriori dettagli, consulta l'articolo su CORB per gli sviluppatori web o la nostra esplicativa approfondita di CORB.

Perché l'isolamento dei siti dovrebbe interessare gli sviluppatori web?

Per la maggior parte, l'isolamento dei siti è una funzionalità del browser dietro le quinte che non è direttamente esposta agli sviluppatori web. Ad esempio, non è necessario imparare una nuova API esposta sul web. In generale, le pagine web non dovrebbero essere in grado di distinguere se vengono eseguite con o senza l'isolamento dei siti.

Tuttavia, ci sono alcune eccezioni a questa regola. L'attivazione dell'isolamento dei siti comporta alcuni effetti collaterali sottili che potrebbero influire sul tuo sito web. Gestiamo un elenco di problemi noti relativi all'isolamento dei siti, e di seguito illustriamo i più importanti.

Il layout a pagina intera non è più sincrono

Con l'isolamento dei siti, non è più garantito che il layout a pagina intera sia sincrono, poiché i frame di una pagina ora possono essere distribuiti su più processi. Ciò potrebbe influire sulle pagine se si presume che una modifica del layout si propaghi immediatamente a tutti i frame della pagina.

Ad esempio, prendiamo in considerazione un sito web denominato fluffykittens.example che comunica con un Widget social ospitato su social-widget.example:

<!-- https://fluffykittens.example/ -->
<iframe src="https://social-widget.example/" width="123"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  iframe.width = 456;
  iframe.contentWindow.postMessage(
    // The message to send:
    'Meow!',
    // The target origin:
    'https://social-widget.example'
  );
</script>

Inizialmente, la larghezza del widget social è pari a 123 pixel.<iframe> Tuttavia, la pagina FluffyKittens modifica la larghezza in 456 pixel (attiva il layout) e invia un messaggio al widget social, che ha il seguente codice:

<!-- https://social-widget.example/ -->
<script>
  self.onmessage = () => {
    console.log(document.documentElement.clientWidth);
  };
</script>

Ogni volta che il widget social riceve un messaggio tramite l'API postMessage, registra la larghezza del suo elemento <html> principale.

Quale valore della larghezza viene registrato? Prima che Chrome attivasse l'isolamento dei siti, la risposta era 456. L'accesso a document.documentElement.clientWidth forza il layout, che in precedenza era sincrono prima dell'attivazione dell'isolamento dei siti da parte di Chrome. Tuttavia, con l'isolamento dei siti abilitato, il nuovo layout del widget social cross-origin ora avviene in modo asincrono in un processo separato. Di conseguenza, ora la risposta può essere anche 123, ovvero il vecchio valore width.

Se una pagina modifica le dimensioni di un <iframe> cross-origin e poi gli invia un postMessage, con la funzionalità Isolamento sito il frame di destinazione potrebbe non conoscere ancora le sue nuove dimensioni al momento della ricezione del messaggio. In generale, questo potrebbe causare il malfunzionamento delle pagine se si presume che una modifica del layout si propaghi immediatamente a tutti i frame della pagina.

In questo caso specifico, una soluzione più solida consisterebbe nell'impostare width nel frame principale e nell'individuare la modifica in <iframe> ascoltando un evento resize.

I gestori di unload potrebbero scadere più spesso

Quando un frame viene visualizzato o chiuso, il vecchio documento e tutti i documenti dei frame secondari in esso incorporati eseguono il rispettivo gestore unload. Se la nuova navigazione avviene nello stesso processo del renderer (ad esempio per una navigazione della stessa origine), i gestori unload del vecchio documento e i relativi frame secondari possono essere eseguiti per un periodo di tempo arbitrariamente lungo prima di consentire il commit della nuova navigazione.

addEventListener('unload', () => {
  doSomethingThatMightTakeALongTime();
});

In questa situazione, gli handler unload in tutti i frame sono molto affidabili.

Tuttavia, anche senza l'isolamento dei siti, alcune navigazioni nel frame principale sono cross-process, il che influisce sul comportamento del gestore dell'unload. Ad esempio, se passi da old.example a new.example digitando l'URL nella barra degli indirizzi, la navigazione a new.example avviene in un nuovo processo. I gestori di unload per old.example e i relativi frame secondari vengono eseguiti nel processo old.example in background, dopo la visualizzazione della pagina new.example, mentre i precedenti gestori di unload vengono chiusi se non vengono terminati entro un determinato timeout. Poiché i gestori dell'unload potrebbero non terminare prima del timeout, il comportamento dell'unload è meno affidabile.

Con l'isolamento dei siti, tutte le navigazioni tra siti diventano in più processi, in modo che i documenti di siti diversi non condividano un processo tra loro. Di conseguenza, la situazione descritta sopra si applica in più casi e i gestori di caricamento in <iframe> hanno spesso i comportamenti in background e di timeout descritti sopra.

Un'altra differenza derivante dall'isolamento dei siti è il nuovo ordinamento parallelo dei gestori di svuotamento: senza l'isolamento dei siti, i gestori di svuotamento vengono eseguiti in un ordine rigoroso dall'alto verso il basso nei frame. Con l'isolamento dei siti, invece, i gestori degli unload vengono eseguiti in parallelo tra diversi processi.

Queste sono conseguenze fondamentali dell'attivazione dell'isolamento dei siti. Il team di Chrome sta lavorando al miglioramento dell'affidabilità dei gestori di svuotamento per i casi d'uso comuni, ove possibile. Siamo inoltre a conoscenza di bug in cui i gestori di unload del frame secondario non sono ancora in grado di utilizzare determinate funzionalità e stanno lavorando per risolverli.

Un caso importante per i gestori di unload è l'invio di ping di fine sessione. Questa operazione viene in genere eseguita come segue:

addEventListener('pagehide', () => {
  const image = new Image();
  img.src = '/end-of-session';
});

Un approccio migliore e più solido alla luce di questa modifica è utilizzare navigator.sendBeacon instead:

addEventListener('pagehide', () => {
  navigator.sendBeacon('/end-of-session');
});

Se hai bisogno di un maggiore controllo sulla richiesta, puoi utilizzare l'opzione keepalive dell'API Fetch:

addEventListener('pagehide', () => {
  fetch('/end-of-session', {keepalive: true});
});

Conclusione

L'isolamento dei siti rende più difficile per i siti web non attendibili accedere o rubare informazioni dai tuoi account su altri siti web, isolando ogni sito in un proprio processo. In questo contesto, CORB tenta di mantenere le risorse di dati sensibili al di fuori del processo del visualizzatore. I nostri consigli riportati sopra ti consentono di ottenere il massimo da queste nuove funzionalità di sicurezza.

Grazie ad Alex Moshchuk, Charlie Reis, Jason Miller, Nasko Oskov, Philip Walton, Shubhie Panicker e Thomas Steiner per aver letto una bozza di questo articolo e averci fornito il loro feedback.