Start · Sprachen · JavaScript · Referenz · Window.postMessage()

Window.postMessage()

Methode

Sendet eine Nachricht sicher an ein anderes <code>Window</code>, z. B. ein iframe, Pop-up oder Opener – auch über Ursprungsgrenzen hinweg.

seit JavaScript Baseline: alle Browser (Options-Objekt-Variante se Kategorie: webapi

Signatur

targetWindow.postMessage(message, targetOrigin, transfer) | targetWindow.postMessage(message, options)

Beschreibung

postMessage() ist der offizielle Weg, um zwischen Fenstern mit unterschiedlichem Ursprung (Protokoll, Host, Port) Daten auszutauschen. Normalerweise verhindert die Same-Origin-Policy, dass ein Skript auf das DOM oder die Variablen eines fremden Fensters zugreift. Über postMessage() kann ein Fenster dem anderen trotzdem gezielt eine Nachricht schicken, die dort als message-Event ankommt.

Typische Einsatzfälle sind eingebettete Widgets (Zahlungsformulare, Karten, Chat-Widgets) in einem <iframe>, OAuth-Anmeldungen per Pop-up, die das Ergebnis an window.opener zurückmelden, oder die Kommunikation zwischen einer App und einer Sandbox-Vorschau. Aufgerufen wird die Methode immer auf dem Zielfenster – etwa iframe.contentWindow, window.parent, window.opener oder dem Rückgabewert von window.open().

Die Nachricht wird mit dem Structured-Clone-Algorithmus kopiert. Du kannst also Objekte, Arrays, Map, Set, Date, Blob, ArrayBuffer usw. senden, aber keine Funktionen, DOM-Knoten oder Klasseninstanzen mit Prototyp. Übertragbare Objekte (ArrayBuffer, MessagePort, ImageBitmap …) lassen sich über transfer ohne Kopie weitergeben. Danach sind sie im Absenderkontext nicht mehr nutzbar.

Der Versand ist asynchron: Das Event wird erst ausgelöst, wenn alle ausstehenden Skripte im Zielfenster abgearbeitet sind. Beim Empfänger musst du event.origin und am besten auch event.source prüfen, bevor du den Daten vertraust.

Parameter

Name Typ Default Beschreibung
$message Pflicht any (structured-cloneable) Die zu sendenden Daten. Sie werden per Structured Clone kopiert. Funktionen und DOM-Knoten sind nicht erlaubt und lösen einen DataCloneError aus.
$targetOrigin string "/" (bei Options-Variante) Ursprung, den das Zielfenster haben muss, z. B. "https://example.com". Stimmt er nicht überein, wird die Nachricht still verworfen. "*" erlaubt jeden Ursprung (unsicher), "/" steht für den eigenen Ursprung.
$transfer Transferable[] [] Liste übertragbarer Objekte (z. B. ArrayBuffer, MessagePort), deren Besitz an den Empfänger übergeht.
$options { targetOrigin?: string, transfer?: Transferable[] } { targetOrigin: "/" } Alternative Schreibweise als Objekt mit targetOrigin und transfer. In neueren Browsern verfügbar.

Beispiele

Eltern-Seite sendet Daten an ein eingebettetes iframe

// Auf https://shop.example
const frame = document.querySelector('#payment-frame');

frame.addEventListener('load', () => {
  frame.contentWindow.postMessage(
    { type: 'INIT', amount: 49.9, currency: 'EUR' },
    'https://pay.example' // nur an diesen Ursprung zustellen
  );
});

iframe empfängt, prüft den Ursprung und antwortet

// Im iframe auf https://pay.example
const ALLOWED_ORIGIN = 'https://shop.example';

window.addEventListener('message', (event) => {
  if (event.origin !== ALLOWED_ORIGIN) return; // fremde Absender ignorieren
  const { type, amount, currency } = event.data ?? {};
  if (type !== 'INIT') return;

  console.log(`Zahlung vorbereitet: ${amount} ${currency}`);
  // Antwort an genau das Fenster, das gesendet hat
  event.source.postMessage({ type: 'READY' }, event.origin);
});
Zahlung vorbereitet: 49.9 EUR

OAuth-Pop-up meldet Ergebnis an den Opener

// Hauptseite
const popup = window.open('https://auth.example/login', 'login', 'width=500,height=600');

const waitForToken = () => new Promise((resolve, reject) => {
  const onMessage = (event) => {
    if (event.origin !== 'https://auth.example' || event.source !== popup) return;
    window.removeEventListener('message', onMessage);
    event.data.error ? reject(new Error(event.data.error)) : resolve(event.data.token);
  };
  window.addEventListener('message', onMessage);
});

const token = await waitForToken();
console.log('Token erhalten:', token.slice(0, 8) + '…');

// Im Pop-up (auf https://auth.example):
// window.opener.postMessage({ token: 'abc123xyz789' }, 'https://app.example');
// window.close();
Token erhalten: abc123xy…

Options-Objekt und Transfer eines ArrayBuffer

const buffer = new ArrayBuffer(1024 * 1024); // 1 MB
const frame = document.querySelector('iframe');

frame.contentWindow.postMessage(
  { kind: 'image-data', buffer },
  { targetOrigin: 'https://viewer.example', transfer: [buffer] }
);

// Der Buffer gehört jetzt dem Empfänger
console.log(buffer.byteLength);

// Wichtig · Fallstricke

Sicherheit – Absender: Gib als targetOrigin immer einen konkreten Ursprung an, wenn du vertrauliche Daten sendest. Mit \"*\" kann die Nachricht bei einem Angreifer landen, falls das Zielfenster inzwischen auf eine andere Seite navigiert wurde, etwa ein umgeleitetes Pop-up.

Sicherheit – Empfänger:

  • Prüfe in jedem message-Handler event.origin gegen eine Whitelist. Jedes Fenster kann dir Nachrichten schicken.
  • Prüfe zusätzlich event.source, wenn du nur ein bestimmtes Fenster erwartest.
  • Behandle event.data als nicht vertrauenswürdige Eingabe: Validiere Typ und Struktur und gib die Daten niemals ungeprüft an innerHTML, eval(), new Function() oder location.href weiter. Sonst drohen DOM-basiertes XSS und Open Redirects.
  • Vergleiche Ursprünge exakt mit ===. Prüfungen wie origin.includes('example.com') oder endsWith() lassen sich mit Domains wie example.com.evil.net umgehen.

Weitere Fallstricke:

  • Ursprünge vergleichen Schema, Host und Port. http:// und https:// sowie www. und die Domain ohne www. gelten als verschieden. Bei einer Abweichung wird die Nachricht still verworfen.
  • Sendest du vor dem load-Event eines iframes, erhält eventuell noch das alte Dokument (about:blank) die Nachricht, und sie geht verloren. Zuverlässiger ist ein Handshake, bei dem das iframe ein „READY“ meldet.
  • Nicht klonbare Werte lösen einen DataCloneError aus. Klasseninstanzen verlieren ihren Prototyp.
  • Header wie Cross-Origin-Opener-Policy: same-origin können window.opener auf null setzen. Dann funktioniert die Pop-up-Kommunikation nicht mehr.
  • Ein iframe mit sandbox ohne allow-same-origin hat den Ursprung \"null\".

Kompatibilität: Die Variante mit targetOrigin funktioniert in allen Browsern. Die Options-Variante ({ targetOrigin, transfer }) gibt es erst in neueren Versionen von Chrome, Firefox und Safari. Für ältere Browser nimm die Variante mit Positionsparametern. Für Worker und MessageChannel gibt es eigene postMessage()-Methoden mit leicht abweichender Signatur (ohne targetOrigin).