Isolamento dei siti per sviluppatori web

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

Che cos'è l'isolamento dei siti?

Su internet, tra le altre cose, puoi guardare video di gatti e gestire portafogli di criptovalute, ma non vorresti che fluffycats.example avesse accesso alle tue preziose criptovalute. Fortunatamente, i siti web in genere non possono accedere ai dati degli altri all'interno del browser grazie al criterio Same-Origin Policy. Tuttavia, i siti web dannosi potrebbero tentare di aggirare questo criterio per attaccare altri siti web e, a volte, vengono trovati bug di sicurezza nel codice del browser che applica il criterio della stessa origine. Il team di Chrome mira a correggere questi bug il più rapidamente possibile.

L'isolamento dei siti è una funzionalità di sicurezza di Chrome che offre un'ulteriore linea di difesa per ridurre le probabilità di successo di questi attacchi. Garantisce che le pagine di siti web diversi vengano sempre inserite in processi diversi, ciascuna 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 side-channel speculativi come Spectre per rubare dati da altri siti. Quando il team di Chrome completa ulteriori applicazioni, l'isolamento dei siti sarà utile anche se la pagina di un utente malintenzionato può violare alcune regole nel suo 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 da vari tipi di bug di sicurezza, come i recenti attacchi al canale laterale Meltdown e Spectre.

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

Blocco lettura multiorigine

Anche se tutte le pagine tra siti vengono inserite in processi separati, le pagine possono comunque richiedere legittimamente alcune sottorisorse tra siti, come immagini e JavaScript. Una pagina web dannosa potrebbe utilizzare un elemento <img> per caricare un file JSON con dati sensibili, come 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 vengono inseriti nella memoria del processo del renderer, dopodiché il renderer nota che non è un formato dell'immagine valido e non esegue il rendering di un'immagine. Tuttavia, l'utente malintenzionato potrebbe sfruttare una vulnerabilità come Spectre per leggere potenzialmente quel blocco di memoria.

Anziché utilizzare <img>, l'utente malintenzionato potrebbe utilizzare anche <script> per trasferire i dati sensibili in memoria:

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

Il blocco della lettura su più origini, o CORB, è una nuova funzionalità di sicurezza che impedisce ai contenuti di balance.json di inserire mai nella memoria della memoria del processo di rendering in base al tipo MIME.

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

  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: *. Le risorse multimediali possono invece essere incluse da qualsiasi origine, anche senza intestazioni CORS permissive.

CORB impedisce al processo del renderer di ricevere una risorsa di dati multiorigine (ad esempio HTML, XML o JSON) se:

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

Se per la risorsa di dati multiorigine non è impostata l'intestazione X-Content-Type-Options: nosniff, CORB tenta di analizzare il corpo della risposta per determinare se si tratta di HTML, XML o JSON. Questa operazione è necessaria perché alcuni server web non sono configurati correttamente 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 avviene ancora in background. Di conseguenza, ha difficoltà a inserire dati tra siti nel processo per rubare una pagina web dannosa.

Per una sicurezza ottimale e per trarre vantaggio da CORB, 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.
  • Disattiva lo sniffing utilizzando l'intestazione X-Content-Type-Options: nosniff. Senza questa intestazione, Chrome esegue una rapida analisi dei contenuti per provare a verificare che il tipo sia corretto, ma poiché ciò commette un errore per consentire l'invio di risposte per evitare di bloccare elementi come i file JavaScript, farai meglio a fare affermativamente la cosa giusta in prima persona.

Per maggiori dettagli, consulta l'articolo CORB per sviluppatori web o la nostra spiegazione approfondita di CORB.

Perché gli sviluppatori web dovrebbero preoccuparsi dell'isolamento dei siti?

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

Tuttavia, ci sono alcune eccezioni a questa regola. L'attivazione dell'isolamento dei siti presenta alcuni piccoli effetti che potrebbero interessare il tuo sito web. Gestiamo un elenco dei problemi noti di isolamento dei siti di cui di seguito analizzeremo quelli più importanti.

Il layout a pagina intera non è più sincrono

Grazie all'isolamento dei siti, non è più garantito che il layout a pagina intera sia sincrono, poiché i frame di una pagina ora possono essere distribuiti in più processi. Questo potrebbe influire sulle pagine se si presume che una modifica del layout si propaga immediatamente a tutti i frame sulla 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 di <iframe> del widget social è di 123 pixel. Poi, però, la pagina FluffyKittens modifica la larghezza in 456 pixel (attivando 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 dell'elemento <html> principale.

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

Se una pagina cambia le dimensioni di un elemento <iframe> multiorigine e le invia un postMessage, con l'isolamento dei siti il frame ricevente potrebbe non conoscere le nuove dimensioni quando riceve il messaggio. Più generalmente, questo potrebbe interrompere le pagine se si presume che una modifica del layout si propaga immediatamente a tutti i frame sulla pagina.

In questo esempio particolare, una soluzione più solida imposterebbe width nel frame principale e rileverebbe la modifica in <iframe> ascoltando un evento resize.

I gestori dell'unload potrebbero scadere con maggiore frequenza

Quando un frame si naviga o si chiude, il vecchio documento e gli eventuali documenti del frame secondario incorporato al suo interno eseguono tutti il proprio gestore unload. Se la nuova navigazione avviene nello stesso processo del renderer (ad esempio, per la navigazione con la stessa origine), i gestori unload del vecchio documento e dei relativi frame secondari possono essere eseguiti per un periodo di tempo arbitrario prima di consentire il commit della nuova navigazione.

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

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

Tuttavia, anche senza l'isolamento dei siti, alcune navigazioni tra i frame principali sono cross-process, il che influisce sul comportamento del gestore di unload. Ad esempio, se passi da old.example a new.example digitando l'URL nella barra degli indirizzi, la navigazione 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, e i vecchi gestori dell'unload vengono terminati se non terminano entro un determinato timeout. Poiché i gestori dell'unload potrebbero non terminare prima del timeout, il comportamento di unload è meno affidabile.

Con l'isolamento dei siti, tutte le navigazioni tra siti diventano cross-process, in modo che i documenti di siti diversi non condividano un processo tra loro. Di conseguenza, la situazione precedente si applica in un maggior numero di casi e i gestori dell'unload in <iframe> spesso hanno i comportamenti di background e timeout descritti in precedenza.

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

Queste sono conseguenze fondamentali dell'attivazione dell'isolamento dei siti. Il team di Chrome sta lavorando per migliorare l'affidabilità dei gestori dell'unload per i casi d'uso comuni, ove possibile. Siamo inoltre consapevoli dei bug per cui i gestori dell'unload dei sottoframe non sono ancora in grado di utilizzare determinate funzionalità e stanno lavorando per risolverle.

Un caso importante per i gestori dell'unload è l'invio dei ping di fine sessione. In genere, questa operazione viene eseguita come segue:

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

Un approccio migliore e più solido alla luce di questo cambiamento consiste nell'utilizzare invece navigator.sendBeacon:

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 dal tuo account su altri siti web isolando ogni sito nel proprio processo. Nell'ambito di questo processo, CORB cerca di escludere dal processo di rendering le risorse dati sensibili. I nostri consigli precedenti ti consentono di sfruttare al meglio queste nuove funzionalità di sicurezza.

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