Skip to content

Instantly share code, notes, and snippets.

@aravindkumarsvg
Last active November 8, 2025 09:32
Show Gist options
  • Select an option

  • Save aravindkumarsvg/eeab62a0c6be096abc446789d15c21d9 to your computer and use it in GitHub Desktop.

Select an option

Save aravindkumarsvg/eeab62a0c6be096abc446789d15c21d9 to your computer and use it in GitHub Desktop.
Various functionalities used in web for communications between windows, documents, contexts

🧭 Communications Between Windows, Documents & Contexts

πŸ“˜ Comprehensive Developer & Security Cheatsheet


🧩 1. Overview

Modern web applications often require communication between multiple browsing contexts β€” windows, iframes, tabs, popups, or even workers.
The browser provides several APIs for this, each suited for different scenarios.


🧱 2. Main Communication APIs

API Context Cross-Origin Support Direction Typical Use Case
postMessage Window ↔ Iframe / Popup βœ… Yes One-to-one Secure cross-document messaging
MessageChannel Any connected contexts βœ… Yes Two-way Dedicated bi-directional pipe
BroadcastChannel Tabs / Frames / Workers (same origin) ❌ No One-to-many Messaging between tabs of same origin
SharedWorker Tabs / Frames (same origin) ❌ No Many-to-one Shared state or caching logic
StorageEvent (localStorage) Tabs (same origin) ❌ No One-to-many Simple tab sync via storage
Service Worker Messaging All pages + worker βœ… Yes Many-to-one Background sync, push handling

🧭 3. postMessage()

πŸ”§ Requirements

Context Reference Example
Iframe iframe.contentWindow const frame = document.getElementById('child').contentWindow;
Popup window.open() const popup = window.open('https://child.com');
Parent window.parent From inside iframe
Opener window.opener From popup
Named Frame window.frames['frameName'] From parent page

🧩 Usage

targetWindow.postMessage(message, targetOrigin, [transfer]);

βœ… Example: Parent ↔ Iframe

// Parent β†’ Iframe
iframe.contentWindow.postMessage({ action: "fetchData" }, "https://child.com");

// Iframe β†’ Parent
window.parent.postMessage({ user: "Alice" }, "https://parent.com");

// Listener
window.addEventListener("message", (event) => {
  if (event.origin !== "https://child.com") return; // Always verify origin
  console.log(event.data);
});

πŸ” Security Checklist

  • βœ… Verify event.origin
  • βœ… Use specific targetOrigin
  • 🚫 Avoid "*" unless local/dev only
  • βœ… Sanitize and validate event.data
  • βœ… Use HTTPS for all message contexts

πŸ”— 4. MessageChannel – Direct Bi-Directional Messaging

Used for private communication between two contexts.

const { port1, port2 } = new MessageChannel();

iframe.contentWindow.postMessage("init", "https://child.com", [port2]);

port1.onmessage = e => console.log("Received:", e.data);

Pros

  • Fast and private (no global broadcast)
  • Full duplex messaging

Cons

  • Setup complexity
  • Manual reference management

πŸ“‘ 5. BroadcastChannel – Multi-Tab or Multi-Frame Communication

Allows all tabs, iframes, or workers from the same origin to communicate.

// Tab 1
const channel = new BroadcastChannel("notifications");
channel.postMessage({ event: "new-message", text: "Hello tabs!" });

// Tab 2
const channel2 = new BroadcastChannel("notifications");
channel2.onmessage = e => console.log("Received:", e.data);

Pros

  • Simple pub/sub pattern
  • Auto-discovers all same-origin tabs

Cons

  • Same-origin only
  • No message persistence after reload

Security Tip:
All participants share trust β€” sanitize incoming data.


βš™οΈ 6. SharedWorker – Centralized Communication Hub

A SharedWorker can serve multiple tabs from the same origin simultaneously.

main.js

const worker = new SharedWorker("worker.js");
worker.port.start();
worker.port.postMessage("hello");
worker.port.onmessage = e => console.log(e.data);

worker.js

onconnect = (e) => {
  const port = e.ports[0];
  port.onmessage = ev => port.postMessage(`Echo: ${ev.data}`);
};

Pros

  • Persistent shared logic or cache
  • Handles multiple connections

Cons

  • Same-origin only
  • Limited browser support in iframes

πŸͺ£ 7. StorageEvent – Communicate via localStorage

Triggered when another tab updates localStorage.

// Tab A
localStorage.setItem("update", JSON.stringify({ msg: "Hi!" }));

// Tab B
window.addEventListener("storage", e => {
  if (e.key === "update") console.log("Got:", JSON.parse(e.newValue));
});

Pros

  • Easiest to implement
  • Works across tabs

Cons

  • Same-origin only
  • No structured clone (string-only)
  • No event in same tab that triggered it

βš™οΈ 8. Service Worker Messaging

Allows persistent communication between pages and their background service worker.

// Client β†’ SW
navigator.serviceWorker.controller.postMessage({ task: "sync" });

// SW β†’ Client(s)
self.clients.matchAll().then(clients => {
  clients.forEach(client => client.postMessage("Done"));
});

Use Case: background sync, notifications, centralized data updates.


🧩 9. Summary Comparison

API Origin Restriction Direction Best For Security Concern
postMessage None (uses targetOrigin) 1↔1 Parent–Child / Popup Origin spoofing
MessageChannel None (paired) 1↔1 Private channel Port leaks
BroadcastChannel Same-origin 1↔N Tabs of same app Data trust
SharedWorker Same-origin N↔1 Shared logic Worker compromise
StorageEvent Same-origin 1↔N Tab sync No data validation
ServiceWorker None (registered scope) N↔1 Background processing Message validation

πŸ” 10. Overall Security Recommendations

  • Validate both origin and source for messages.
  • Use structured clone safe data (no DOM elements/functions).
  • Restrict iframe embedding using X-Frame-Options or CSP frame-ancestors.
  • Don’t use "*" in targetOrigin.
  • Apply sandbox attributes and proper allow permissions for iframes.
  • Avoid sensitive data in cross-origin messages.

🧠 11. Quick Decision Guide

Use Case Recommended API
Parent ↔ Iframe postMessage
Tabs (same origin) BroadcastChannel
Popup ↔ Opener postMessage
Multiple tabs share a worker SharedWorker
Background sync ServiceWorker
Simple tab-to-tab state share StorageEvent
Private channel MessageChannel

🧭 postMessage() Cheatsheet

πŸ“˜ For Developers & Security Engineers


🧩 1. Overview

window.postMessage() provides a secure, browser-supported communication channel between:

  • Windows and their child iframes
  • Popups and their opener windows
  • Tabs (through shared references like window.opener, window.parent, or window.frames[])
  • Service workers, extensions, and sandboxed contexts (via MessageChannel)

This API is critical for cross-origin messaging and event-based data exchange.


βš™οΈ 2. Initial Requirements

Before sending or receiving messages, you need a window reference to communicate with.

Context How to Get Reference Example
Iframe (child) Use iframe.contentWindow const child = document.getElementById('frame').contentWindow;
Popup / New Tab Use window.open() result const popup = window.open('https://child.com');
Parent Window From inside iframe const parent = window.parent;
Specific Frame From parent page const frame = window.frames['frameName'];
Opener Window From popup const opener = window.opener;

You can only send messages to windows you can reference β€” there’s no β€œbroadcast” to all tabs.


πŸš€ 3. Syntax

targetWindow.postMessage(message, targetOrigin, [transfer]);
Parameter Description
message Any serializable data (string, object, array, etc.)
targetOrigin The expected destination origin (e.g., "https://child.com"). Use "*" only in development.
transfer Optional: list of transferable objects (e.g., ArrayBuffer, MessagePort).

πŸ’‘ 4. Basic Example – Parent ↔ Iframe

Parent β†’ Child

const iframe = document.getElementById("child");
iframe.contentWindow.postMessage({ action: "getUser" }, "https://child.com");

Child β†’ Parent

window.parent.postMessage({ user: "Alice" }, "https://parent.com");

Parent Listener

window.addEventListener("message", (event) => {
  if (event.origin !== "https://child.com") return; // βœ… Always verify sender
  console.log("Message from child:", event.data);
});

πŸ“¦ 5. Message Event Properties

Property Description
event.data The actual message payload
event.origin The sender’s origin (scheme + host + port)
event.source Reference to the sender window
event.ports Array of transferred MessagePort objects

🧱 6. Common Communication Patterns

Pattern Example Description
Parent ↔ Iframe window.parent, iframe.contentWindow Cross-origin or same-origin frame messaging
Popup ↔ Opener window.opener When a site opens a new tab/popup
Iframe ↔ Iframe (via parent) Relay messages through parent window
Two independent tabs Use BroadcastChannel or ServiceWorker postMessage alone can’t connect tabs

πŸ” 7. Security Guidelines

βœ… Always specify targetOrigin – Avoid "*" unless absolutely necessary.
βœ… Always verify event.origin – Confirm sender domain matches expected origin.
βœ… Avoid sending sensitive data unless over HTTPS and verified recipient.
βœ… Sanitize input – Never trust messages without validation.
βœ… Restrict iframe permissions using attributes like sandbox, allow-same-origin, allow-scripts.
βœ… Disable or limit third-party framing with CSP headers (frame-ancestors).


⚠️ 8. Common Vulnerabilities

Risk Description Mitigation
Origin Spoofing Attacker sends fake messages from malicious origin Validate event.origin before acting
XSS Relay Malicious script in child sends payload to parent Sanitize event.data
Data Leak Using "*" exposes data to any site Use explicit targetOrigin
Logic Abuse Message handler performs unintended actions Implement action whitelists and strict schema checks

🧠 9. Advanced Usage – Transferable Objects

const { port1, port2 } = new MessageChannel();
iframe.contentWindow.postMessage("init", "https://child.com", [port2]);

port1.onmessage = e => console.log("From iframe:", e.data);

This enables bi-directional communication channels beyond basic postMessage.


🧩 10. Debugging Tips

Tool / Method Use
console.log(event.origin, event.data) Log inbound messages
Browser DevTools β†’ Frames Inspect window/frame hierarchy
Network Tab postMessage does not show in network logs (client-only)
CSP + Sandbox Headers Restrict iframes and external message access

🧾 11. Summary Table

Operation Requirement Security Check Example
Send message Reference to target window targetOrigin verification target.postMessage(data, origin)
Receive message addEventListener('message') event.origin validation if (event.origin === 'https://trust.com')
Bidirectional channel MessageChannel Validate message source const {port1, port2} = new MessageChannel()

βœ… 12. Quick Best Practices

  • Use explicit origins – never "*" in production.
  • Validate both origin and source.
  • Sanitize data if user-controlled.
  • Don’t expose privileged APIs directly through message handlers.
  • Use structured clone safe data (no functions, DOM nodes).
  • Enable sandbox and CSP for framed pages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment