HTML - Messagerie web

-

Types de messagerie Web

Messagerie par canal

La messagerie par canal permet à deux ou plusieurs contextes de navigation (fenêtres, onglets ou iframes) de communiquer entre eux, même s'ils sont sur des origines différentes. Elle utilise un objet de canal de message pour établir un lien entre les contextes et envoyer des messages entre eux.

La messagerie par canal est utile lorsque vous devez établir un lien direct et bidirectionnel entre les contextes. Par exemple, vous pouvez l'utiliser pour permettre à une fenêtre parente de contrôler un iframe ou pour permettre à deux onglets de partager des données en temps réel.

Conseil: Exemple de messagerie par canal

// Dans le premier contexte de navigation
const channel = new MessageChannel();
const port1 = channel.port1;
const port2 = channel.port2;

// Envoyer port2 au deuxième contexte de navigation
window.postMessage('init', '*', [port2]);

// Écouter les messages sur port1
port1.onmessage = (event) => {
  console.log('Message reçu:', event.data);
};

// Dans le deuxième contexte de navigation
window.onmessage = (event) => {
  if (event.data === 'init') {
    const port2 = event.ports[0];
    port2.onmessage = (event) => {
      console.log('Message reçu:', event.data);
    };
    port2.postMessage('Bonjour du deuxième contexte!');
  }
};

Messagerie inter-documents

La messagerie inter-documents, également connue sous le nom de postMessage, permet à différents contextes de navigation (fenêtres, onglets ou iframes) de communiquer même s'ils sont sur des origines différentes. Elle utilise la méthode postMessage() pour envoyer un événement de message au contexte récepteur, qui peut ensuite le gérer à l'aide d'un écouteur d'événements.

La messagerie inter-documents est utile lorsque vous avez besoin de messages unidirectionnels entre les contextes. Par exemple, lorsqu'une fenêtre parente doit demander à un iframe de faire quelque chose ou lorsqu'un onglet doit envoyer des données à un autre onglet.

Conseil: Exemple de messagerie inter-documents

// Dans le contexte d'envoi
const targetWindow = window.parent; // Ou window.opener, ou document.getElementById('myIframe').contentWindow
targetWindow.postMessage('Bonjour de l'expéditeur!', '*');

// Dans le contexte de réception
window.addEventListener('message', (event) => {
  if (event.origin === 'http://example.com') {
    console.log('Message reçu:', event.data);
  }
});

Web Workers

Les Web Workers exécutent des scripts en arrière-plan sans affecter les performances de la page. Ils permettent un traitement lourd dans un thread séparé afin que la page principale reste réactive.

Les Web Workers sont utiles pour les tâches qui prennent du temps comme les calculs complexes et le traitement de données.

Conseil: Exemple de Web Workers

// Dans le script principal
const worker = new Worker('worker.js');
worker.onmessage = (event) => {
  console.log('Message reçu du worker:', event.data);
};
worker.postMessage('Bonjour du script principal!');

// Dans worker.js
self.onmessage = (event) => {
  console.log('Message reçu dans le worker:', event.data);
  self.postMessage('Bonjour du worker!');
};

Considérations de sécurité

Lors de l'utilisation de la messagerie Web, soyez conscient des risques potentiels de sécurité et suivez les meilleures pratiques pour une mise en œuvre sécurisée.

Un risque principal avec la messagerie Web est les attaques par script intersite (XSS). Si vous ne validez pas et ne désinfectez pas les données reçues via les messages, un attaquant pourrait envoyer du code malveillant qui s'exécuterait sur votre page. Cela pourrait lui permettre de voler des données sensibles, d'effectuer des actions au nom de l'utilisateur ou de prendre le contrôle de la page.

Conseil: HTML code example for XSS risk

<p>This    is   a   paragraph   with    extra   spaces.</p>

Lorsqu'un navigateur affiche ce code, il présentera le texte comme suit :

This is a paragraph with extra spaces.

Pour prévenir les attaques XSS, validez et désinfectez toujours les données reçues via les messages. Ne supposez pas que les données sont sûres simplement parce qu'elles proviennent d'une autre fenêtre ou d'un autre worker que vous contrôlez. Traitez toutes les données reçues comme des entrées non fiables et gérez-les en conséquence.

Un autre risque survient lors de l'utilisation de la messagerie Web pour communiquer entre différentes origines. Soyez prudent quant aux origines auxquelles vous faites confiance. Si vous acceptez des messages de n'importe quelle origine sans vérification, un attaquant pourrait envoyer des messages depuis un site malveillant qui tromperaient votre page en lui faisant faire quelque chose qu'elle ne devrait pas. Pour réduire ce risque, vérifiez toujours la propriété origin de l'événement de message et n'acceptez que les messages provenant d'origines de confiance.

Lors de l'utilisation de la messagerie par canal, sachez que tout contexte recevant un port de message a un accès complet à ce canal. Cela signifie qu'ils peuvent envoyer des messages sur le canal et même le fermer. Donc, ne partagez les ports de message qu'avec des contextes en lesquels vous avez pleinement confiance.

Avec les Web Workers, un risque principal est qu'un worker pourrait se bloquer ou utiliser trop de ressources s'il se retrouve dans une boucle infinie ou essaie d'effectuer trop de travail. Pour éviter cela, utilisez la méthode Worker.terminate() pour arrêter un worker immédiatement si nécessaire. Structurez votre code de worker pour répondre rapidement aux messages et évitez les tâches de longue durée.

Conseil: Using Worker.terminate() method

var myWorker = new Worker('worker.js');

// Terminate the worker after 5 seconds
setTimeout(function() {
    myWorker.terminate();
}, 5000);

Ce code arrête le worker après un temps spécifié pour éviter une surutilisation des ressources.

Voici quelques bonnes pratiques pour une messagerie Web sécurisée :

  • Validez et désinfectez toujours les données de message reçues
  • N'acceptez que les messages provenant d'origines de confiance
  • Soyez prudent lors du partage des ports de message
  • Utilisez Worker.terminate() pour arrêter les workers qui se comportent mal
  • Gardez votre code de worker ciblé et réactif
  • N'utilisez pas la messagerie Web pour partager des données sensibles sauf si nécessaire
  • Utilisez le chiffrement pour les données sensibles si nécessaire
  • Testez minutieusement votre code de messagerie Web pour détecter les vulnérabilités potentielles

Compatibilité avec les navigateurs

La plupart des navigateurs web modernes prennent en charge la messagerie web. Cela inclut Chrome, Firefox, Safari et Internet Explorer 11 et versions ultérieures. L'API WebSocket et les événements envoyés par le serveur, utilisés pour la messagerie en temps réel, sont également pris en charge dans la plupart des navigateurs.

Les navigateurs plus anciens peuvent avoir une prise en charge limitée ou inexistante de certaines fonctionnalités de messagerie web. Par exemple :

  • Internet Explorer 8 et les versions antérieures ne prennent pas en charge la méthode window.postMessage() utilisée dans la messagerie inter-documents.
  • Internet Explorer 10 et les versions antérieures ne prennent pas en charge les Web Workers.
  • Internet Explorer ne prend pas en charge la messagerie par canal.

Si vous devez prendre en charge des navigateurs plus anciens, vous devrez peut-être utiliser des solutions de contournement ou des alternatives. Voici quelques options :

  • Pour la messagerie inter-documents dans les anciennes versions d'IE, vous pouvez utiliser une bibliothèque comme easyXDM qui fournit un transport de secours utilisant des iframes et la propriété location.hash.

Conseil: Exemple utilisant la bibliothèque easyXDM

// Dans le contexte d'envoi
var socket = new easyXDM.Socket({
  remote: "http://example.com/remote.html",
  onMessage: function(message, origin) {
    console.log("Message reçu :", message);
  }
});
socket.postMessage("Bonjour de l'expéditeur !");

// Dans le contexte de réception (remote.html)
var socket = new easyXDM.Socket({
  onMessage: function(message, origin) {
    console.log("Message reçu :", message);
  }
});
  • Pour les Web Workers dans IE10 et versions antérieures, vous pouvez détecter la prise en charge et fournir une alternative qui exécute le script dans le thread principal à la place.

Conseil: Exemple d'alternative pour Web Workers

if (typeof(Worker) !== "undefined") {
  // Web Workers pris en charge, utiliser le worker
  var worker = new Worker("worker.js");
} else {
  // Web Workers non pris en charge, exécuter le script dans le thread principal
  var workerFallbackScript = document.createElement('script');
  workerFallbackScript.src = 'worker.js';
  document.body.appendChild(workerFallbackScript);
}

Pour les alternatives à la messagerie par canal : Vous pouvez utiliser d'autres techniques de messagerie comme la messagerie inter-documents ou une solution basée sur un serveur lorsque la messagerie par canal n'est pas disponible.

Il est important de tester votre code de messagerie web dans tous les navigateurs que vous prévoyez de prendre en charge. Utilisez la détection de fonctionnalités pour vérifier la prise en charge et fournir des alternatives appropriées si nécessaire pour offrir une bonne expérience à tous vos utilisateurs.

Le paysage des navigateurs s'améliore constamment. La plupart des utilisateurs utilisent maintenant des navigateurs modernes avec de nombreuses fonctionnalités. Ainsi, bien que les alternatives pour les anciens navigateurs puissent encore être nécessaires parfois, elles deviennent moins cruciales au fil du temps à mesure que l'utilisation des navigateurs obsolètes continue de diminuer. Voici la traduction en français :

Exemples pratiques

Application de chat en temps réel

La création d'une application de chat en temps réel montre la puissance de la messagerie Web. Voici un guide pour créer une application de chat basique en utilisant la messagerie par canaux et les Web Workers :

  1. Mettez en place la structure HTML pour l'interface de chat, y compris un champ de saisie pour les messages et un conteneur pour afficher l'historique du chat.

  2. Créez un nouveau Web Worker pour gérer le traitement et le stockage des messages. Ce worker recevra les messages du script principal, les stockera et renverra l'historique du chat mis à jour lorsqu'il sera demandé.

Conseil: Web Worker pour le chat (chat_worker.js)

let chatHistory = [];

self.onmessage = (event) => {
  if (event.data.type === 'newMessage') {
    chatHistory.push(event.data.message);
    self.postMessage({ type: 'updateHistory', history: chatHistory });
  } else if (event.data.type === 'getHistory') {
    self.postMessage({ type: 'updateHistory', history: chatHistory });
  }
};
  1. Dans le script principal, créez un nouveau canal de messagerie et envoyez l'un des ports au worker.

Conseil: Script principal (script.js)

const chatWorker = new Worker('chat_worker.js');
const channel = new MessageChannel();
chatWorker.postMessage({ type: 'init', port: channel.port1 }, [channel.port1]);
  1. Configurez des écouteurs d'événements pour la saisie de messages et la communication par canal. Lorsqu'un nouveau message est saisi, envoyez-le au worker via le canal. Écoutez les mises à jour de l'historique provenant du worker et affichez-les dans l'interface de chat.

Conseil: Écouteurs d'événements et messagerie

const messageInput = document.getElementById('messageInput');
const chatContainer = document.getElementById('chatContainer');

channel.port2.onmessage = (event) => {
  if (event.data.type === 'updateHistory') {
    const messagesHTML = event.data.history.map(message => `<p>${message}</p>`).join('');
    chatContainer.innerHTML = messagesHTML;
  }
};

messageInput.addEventListener('keypress', (event) => {
  if (event.key === 'Enter') {
    const message = messageInput.value;
    channel.port2.postMessage({ type: 'newMessage', message });
    messageInput.value = '';
  }
});
  1. Lors du chargement de la page, demandez l'historique initial du chat au worker.

Conseil: Demande de l'historique initial du chat

chatWorker.postMessage({ type: 'getHistory' });

Avec ces étapes en place, vous avez une application de chat en temps réel basique qui utilise la messagerie Web pour communiquer entre le script principal et le Web Worker.

Communication inter-domaines

La messagerie Web peut également permettre la communication entre différents domaines en utilisant la messagerie inter-documents :

  1. Dans la fenêtre parente, créez un iframe avec l'attribut src défini sur l'URL de la page avec laquelle vous souhaitez communiquer.

Conseil: Fenêtre parente (parent.html)

<iframe id="myIframe" src="https://example.com/iframe.html"></iframe>
  1. Dans le script de l'iframe, écoutez les événements de message et traitez-les en fonction du format de données attendu.

Conseil: Script de l'iframe (iframe.js)

window.addEventListener('message', function(event) {
  if (event.origin === 'https://example.com' && event.data.type === 'userData') {
      console.log('Données utilisateur reçues :', event.data.value);
   }
});
  1. Dans le script de la fenêtre parente, obtenez une référence à la fenêtre de l'iframe et envoyez des messages en utilisant la méthode postMessage().

Conseil: Script de la fenêtre parente (parent.js)

const iframeWindow= document.getElementById('myIframe').contentWindow;
const userData= { name:'John Doe', age :30 };

document.getElementById("myIframe").addEventListener("load", () =>{
   iframeWindow.postMessage({type :'userData ', value :userData },'https://example.com ');
});

Avec cette configuration, la fenêtre parente peut envoyer des messages contenant des données utilisateur à l'iframe, et l'iframe peut écouter ces messages et les traiter en conséquence. Cela permet une communication sécurisée entre deux contextes même s'ils sont hébergés sur des domaines différents.

Lors de l'utilisation de la messagerie inter-documents, validez l'origine des messages reçus en vous assurant qu'ils proviennent de sources de confiance, prévenant ainsi les attaques par script intersite (XSS) et d'autres vulnérabilités de sécurité.