Isolation de sites pour les développeurs Web

Chrome 67 sur ordinateur dispose d'une nouvelle fonctionnalité appelée isolation de sites activée par défaut. Cet article explique en quoi consiste l'isolation de sites, pourquoi elle est nécessaire et pourquoi les développeurs Web doivent en tenir compte.

Qu'est-ce que l'isolation de sites ?

Internet permet, entre autres, de regarder des vidéos de chats et de gérer des portefeuilles de cryptomonnaies, mais il est impossible que fluffycats.example ait accès à vos précieuses cryptocoins. Heureusement, les sites Web ne peuvent généralement pas accéder aux données des autres dans le navigateur grâce aux règles d'origine commune. Néanmoins, des sites Web malveillants peuvent tenter de contourner cette règle pour attaquer d'autres sites Web. De temps à autre, des bugs de sécurité sont détectés dans le code du navigateur qui applique la règle Same-Origin. L'équipe Chrome s'efforce de corriger ces bugs le plus rapidement possible.

L'isolation de sites est une fonctionnalité de sécurité de Chrome qui offre une ligne de défense supplémentaire pour réduire les chances de réussite de telles attaques. Il garantit que les pages de différents sites Web sont toujours placées dans des processus différents, chacun s'exécutant dans un bac à sable qui limite ce que le processus est autorisé à faire. Il empêche également le processus de recevoir certains types de données sensibles provenant d'autres sites. Par conséquent, avec l'isolation de sites, il est beaucoup plus difficile pour un site Web malveillant d'utiliser des attaques spéculatives sur les canaux secondaires, comme Spectre, pour dérober des données à d'autres sites. À mesure que l'équipe Chrome met en œuvre des mesures supplémentaires, l'isolation de sites sera également utile même si la page d'un pirate informatique peut enfreindre certaines règles de son propre processus.

L'isolation de sites empêche les sites Web non approuvés d'accéder aux informations de vos comptes ou de les voler sur d'autres sites Web. Elle offre une protection supplémentaire contre divers types de bugs de sécurité, tels que les attaques par canal auxiliaire Meltdown et Spectre.

Pour en savoir plus sur l'isolation de sites, consultez notre article sur le blog Google sur la sécurité.

Blocage de lecture multi-origine

Même lorsque toutes les pages intersites sont placées dans des processus distincts, les pages peuvent toujours demander légitimement des sous-ressources intersites, telles que des images et JavaScript. Une page Web malveillante peut utiliser un élément <img> pour charger un fichier JSON contenant des données sensibles, telles que votre solde bancaire:

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

Sans l'isolation de sites, le contenu du fichier JSON est ajouté à la mémoire du processus de rendu. Le moteur de rendu remarque alors qu'il ne s'agit pas d'un format d'image valide et qu'il n'affiche pas d'image. Mais le pirate informatique pourrait ensuite exploiter une faille telle que Spectre pour potentiellement lire ce fragment de mémoire.

Au lieu d'utiliser <img>, le pirate informatique peut également utiliser <script> pour conserver les données sensibles en mémoire:

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

Le blocage de lecture multi-origine (CORB) est une nouvelle fonctionnalité de sécurité qui empêche le contenu de balance.json d'entrer dans la mémoire de la mémoire de processus du moteur de rendu en fonction de son type MIME.

Examinons plus en détail le fonctionnement de CORB. Un site Web peut demander deux types de ressources à un serveur:

  1. Ressources de données telles que les documents HTML, XML ou JSON
  2. Ressources multimédias telles que des images, JavaScript, CSS ou des polices

Un site Web peut recevoir des ressources de données de sa propre origine ou d'autres origines avec des en-têtes CORS permissifs, tels que Access-Control-Allow-Origin: *. En revanche, les ressources multimédias peuvent être incluses depuis n'importe quelle origine, même sans en-têtes CORS permissifs.

CORB empêche le processus du moteur de rendu de recevoir une ressource de données multi-origines (HTML, XML ou JSON) dans les cas suivants:

  • la ressource comporte un en-tête X-Content-Type-Options: nosniff.
  • CORS n'autorise pas explicitement l'accès à la ressource

Si l'en-tête X-Content-Type-Options: nosniff n'est pas défini pour la ressource de données multi-origines, CORB tente de renifler le corps de la réponse pour déterminer s'il s'agit de code HTML, XML ou JSON. Cela est nécessaire, car certains serveurs Web sont mal configurés et diffusent des images en tant que text/html, par exemple.

Les ressources de données bloquées par la règle CORB sont présentées au processus comme vides, bien que la requête s'effectue toujours en arrière-plan. Par conséquent, une page Web malveillante a du mal à récupérer des données intersites dans son processus de vol.

Pour une sécurité optimale et des avantages du CORB, nous vous recommandons de suivre ces conseils:

  • Marquez les réponses avec l'en-tête Content-Type approprié. (Par exemple, les ressources HTML doivent être diffusées en tant que text/html, les ressources JSON avec un type JSON MIME et les ressources XML avec un type XML MIME.)
  • Désactivez la détection à l'aide de l'en-tête X-Content-Type-Options: nosniff. Sans cet en-tête, Chrome effectue une analyse rapide du contenu pour vérifier que le type de contenu est correct. Toutefois, étant donné que cela vise à autoriser les réponses pour éviter de bloquer des éléments tels que les fichiers JavaScript, il vaut mieux faire vous-même les informations appropriées.

Pour en savoir plus, consultez l'article sur la fonctionnalité CORB pour les développeurs Web ou notre présentation détaillée de la fonctionnalité CORB.

Pourquoi les développeurs Web doivent-ils s'intéresser à l'isolation de sites ?

Dans la plupart des cas, l'isolation de sites est une fonctionnalité de navigateur exécutée en arrière-plan, qui n'est pas directement exposée aux développeurs Web. Il n'y a pas de nouvelle API exposée sur le Web à apprendre, par exemple. En général, les pages Web ne doivent pas faire la différence lorsqu'elles sont diffusées avec ou sans l'isolation de sites.

Il existe toutefois quelques exceptions à cette règle. L'activation de l'isolation de sites s'accompagne de quelques effets secondaires subtils qui pourraient avoir une incidence sur votre site Web. Nous tenons à jour une liste des problèmes connus liés à l'isolation de sites, dont les plus importants sont détaillés ci-dessous.

La mise en page pleine page n'est plus synchrone

Avec l'isolation de sites, la mise en page pleine page n'est plus synchrone, car les cadres d'une page peuvent désormais être répartis sur plusieurs processus. Cela peut avoir un impact sur les pages si elles supposent qu'une modification de mise en page se propage immédiatement à tous les frames.

Prenons l'exemple d'un site Web nommé fluffykittens.example qui communique avec un widget de réseau social hébergé sur 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>

Au départ, la largeur de l'élément <iframe> du widget de réseau social est de 123 pixels. Toutefois, la page FluffyKittens change la largeur en 456 pixels (mise en page de déclenchement) et envoie un message au widget de réseau social, qui contient le code suivant:

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

Chaque fois que le widget de réseau social reçoit un message via l'API postMessage, il enregistre la largeur de son élément <html> racine.

Quelle valeur de largeur est consignée ? Avant l'activation de l'isolation de sites dans Chrome, la réponse était 456. L'accès à document.documentElement.clientWidth force la mise en page, qui était synchrone avant l'activation de l'isolation de sites dans Chrome. Toutefois, lorsque l'isolation de sites est activée, la remise en page des widgets de réseaux sociaux multi-origines s'effectue désormais de manière asynchrone dans un processus distinct. Par conséquent, la réponse peut désormais être 123, c'est-à-dire l'ancienne valeur width.

Si une page modifie la taille d'un <iframe> multi-origine, puis lui envoie un postMessage, avec l'isolation de sites, il est possible que le frame récepteur ne connaisse pas encore sa nouvelle taille à la réception du message. Plus généralement, cela peut endommager les pages si elles supposent qu'une modification de mise en page se propage immédiatement à tous les cadres de la page.

Dans cet exemple, une solution plus robuste définirait width dans la trame parente et détecterait cette modification dans la <iframe> en écoutant un événement resize.

Décharger les gestionnaires peut expirer plus souvent

Lorsqu'un frame parcourt ou se ferme, l'ancien document ainsi que tous les documents du sous-frame qui y sont intégrés exécutent leur gestionnaire unload. Si la nouvelle navigation se produit dans le même processus de moteur de rendu (par exemple, pour une navigation de même origine), les gestionnaires unload de l'ancien document et de ses sous-frames peuvent s'exécuter pendant une durée arbitrairement longue avant d'autoriser la nouvelle navigation à valider.

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

Dans ce cas, les gestionnaires unload dans tous les frames sont très fiables.

Toutefois, même sans l'isolation de sites, certaines navigations dans les frames principaux sont multiprocessus, ce qui affecte le comportement du gestionnaire de déchargement. Par exemple, si vous passez de old.example à new.example en saisissant l'URL dans la barre d'adresse, la navigation new.example se produit dans un nouveau processus. Les gestionnaires de déchargement pour old.example et ses sous-frames s'exécutent dans le processus old.example en arrière-plan, après l'affichage de la page new.example, et les anciens gestionnaires de déchargement sont arrêtés s'ils ne se terminent pas dans un certain délai. Étant donné que les gestionnaires de déchargement peuvent ne pas se terminer avant l'expiration du délai, le comportement de déchargement est moins fiable.

Avec l'isolation de sites, toutes les navigations intersites deviennent multiprocessus, de sorte que les documents provenant de différents sites ne partagent pas de processus entre eux. Par conséquent, la situation ci-dessus s'applique dans davantage de cas, et les gestionnaires de déchargement dans les <iframe> ont souvent les comportements d'arrière-plan et de délai avant expiration décrits ci-dessus.

Une autre différence résultant de l'isolation de sites est le nouvel ordre parallèle des gestionnaires de déchargement : sans l'isolation de sites, les gestionnaires de déchargement s'exécutent dans un ordre descendant strict entre les frames. Mais avec l'isolation de sites, les gestionnaires de déchargement s'exécutent en parallèle sur différents processus.

Il s'agit des conséquences fondamentales de l'activation de l'isolation de sites. Dans la mesure du possible, l'équipe Chrome s'efforce d'améliorer la fiabilité des gestionnaires de déchargement pour les cas d'utilisation courants. Nous avons également connaissance des bugs qui empêchaient les gestionnaires de déchargement des sous-frames d'utiliser certaines fonctionnalités et nous nous efforçons de les résoudre.

L'envoi de pings de fin de session est un cas important pour les gestionnaires de déchargement. Pour ce faire, procédez comme suit:

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

Compte tenu de ce changement, une approche plus robuste consiste à utiliser plutôt navigator.sendBeacon:

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

Si vous avez besoin de mieux contrôler la requête, vous pouvez utiliser l'option keepalive de l'API Fetch:

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

Conclusion

L'isolation de sites empêche les sites Web non fiables d'accéder aux informations de vos comptes ou de les voler sur d'autres sites, car chaque site est isolé dans son propre processus. CORB tente alors d'exclure les ressources de données sensibles du processus du moteur de rendu. Les recommandations ci-dessus vous permettent de tirer le meilleur parti de ces nouvelles fonctionnalités de sécurité.

Merci à Alex Moshchuk, Charlie Reis, Jason Miller, Nasko Oskov, Philip Walton, Shubhie Panicker et Thomas Steiner d'avoir lu une version préliminaire de cet article et de nous avoir fait part de leurs commentaires.