window.postMessage

window.postMessage() は、 Window オブジェクト間で安全にクロスドメイン通信を可能にするためのメソッドです。例えば、ポップアップとそれを表示したページの間や、iframe とそれが埋め込まれたページの間での通信に使うことができます。

通常、異なった複数のページでのスクリプトはそれらが実行されたページが同じプロトコル、ポート番号、ホストである場合に限りお互いにアクセスすることが可能です ("同一オリジンポリシー" とも呼ばれます)。正しく使用した window.postMessage はこの制限を安全に回避するための制御された仕組みを提供します。

大まかには、ウィンドウが他のウィンドウへの参照を取得できる場合 ( targetWindow = window.opener など)、targetWindow.postMessage() を使って MessageEvent をそのウィンドウ上で配信することができます。受け取ったウィンドウでは必要に応じて自由にイベントを処理することができます。window.postMessage() に渡された引数 (“message”) はイベントオブジェクトを通して対象のウィンドウに公開されます

構文

targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
メッセージを受信するウィンドウへの参照。参照を取得する方法には以下のようなものがあります:
message
他のウィンドウに送られるデータ。データは the structured clone algorithm に従ってシリアル化されます。つまり、手動でシリアル化することなく様々なデータオブジェクトを渡すことができます。
targetOrigin
イベントを配信する otherWindow のオリジンを "*" というリテラル文字列(制限しないことを示します)か URI のいずれかで指定します。もしイベントの配信が予約される時点で、targetWindow のドキュメントのスキーマ、ホスト名、あるいはポートが targetOrigin で指定されたものにマッチしない場合、そのイベントは配信されません。3 つすべてがマッチした場合にだけイベントが配信されます。この仕組みはメッセージがどこに送られるかを制御できるようにしています。例えば postMessage をパスワードを送るために利用する場合、悪意のある第三者によるパスワードの傍受を防ぐため、そのメッセージを受け取るべき受信者のオリジンと一致する URI をこの引数に指定しておくことが非常に重要になります。 送信先ウィンドウのドキュメントがどこに配置されるのかを知っている場合、* ではなく具体的な targetOrigin を指定してください。具体的なターゲットを指定しない場合、相手が悪意を持ったサイトであっても、送信したデータが公開されることを意味します。
transfer Optional
メッセージと一緒に転送される Transferable オブジェクトのシーケンス。これらのオブジェクトの所有権は送信先に移動され、送信元では使えなくなります。

配信されるイベント

otherWindow は以下の JavaScript を実行することで、配信されたメッセージを受け取ることができます。

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event) {
  if (event.origin !== "http://example.org:8080")
    return;

  // ...
}

配信されたメッセージは以下のプロパティを持ちます。

data
他のウィンドウから渡されたメッセージを保持しているオブジェクト。
origin
postMessage が呼び出されたときにメッセージを送るウィンドウのオリジン。この文字列は、プロトコルと "://"、ホスト名(存在する場合)、そして、":" の後に続くポート番号(デフォルトポートと指定するポートが異なる場合)が連結されたものです。典型的なオリジンの例は https://example.org (この場合のポートは 443)、http://example.net (この場合のポートは 80)、そして http://example.com:8080。このオリジン生成元はそのウィンドウの現在もしくは将来のオリジンであることを保証していないことに注意してください。postMessage が呼び出された時とは異なる場所に移動しているかもしれません。
source
メッセージを送った window オブジェクトへの参照。これを使うことでオリジンの異なる二つのウィンドウ間で双方向の通信を確立することができます。

セキュリティの考慮事項

他のサイトからメッセージを受け取りたくない場合、message イベントに対して一切イベントリスナーを追加しないでください。これはセキュリティ的な問題を避けるための完全にフールプルーフな方法です。

他のサイトからメッセージを受け取りたい場合、origin あるいは source プロパティを用いて常に送信者の識別情報を確かめてください。任意のウィンドウ(例えば、http://evil.example.com も含む)は任意の他のウィンドウにメッセージを送ることができ、見知らぬ送信者が悪意あるメッセージを送らない保証はありません。識別情報を確かめても、常に受け取ったメッセージの構文を確かめるべきです。さもなければ、信頼されたメッセージだけを送るとして信頼されたサイトにセキュリティホールが存在した場合に、クロスサイトスクリプティングのセキュリティホールをあなたのサイトに開けることになり得ます。

他のウィンドウに postMessage でデータを送信する場合、 * ではなく、常に具体的なターゲットオリジンを指定してください。 悪意を持ったサイトはあなたの知らないうちに送信先ウィンドウの場所を変更することができ、そのまま postMessage で送信されたデータを傍受することができてしまいます。

/*
 * <http://example.com:8080> にある、window A のスクリプト:
 */

var popup = window.open(/* ポップアップの詳細 */);

// ポップアップブロッカーでブロックされず、ポップアップが完全にロードされたとき

// ウィンドウがその場所を変更していない場合、これは何もしません。
popup.postMessage("ユーザー名は 'bob' 、パスワードは 'secret' です",
                  "https://secure.example.net");

// ウィンドウがその場所を変更していない場合、
//これはポップアップに送るメッセージのキューに追加します。
popup.postMessage("hello there!", "http://example.com");

function receiveMessage(event)
{
  // このメッセージの送信者は信頼している者か?(例えば、最初開いたものと違
  // うかもしれません)。
  if (event.origin !== "http://example.com")
    return;

  // event.source は popup
  // event.data は "hi there yourself!  the secret response is: rheeeeet!"
}
window.addEventListener("message", receiveMessage, false);
/*
 * <http://example.org> で実行される popup のスクリプト:
 */

// postMessage が呼び出された後に呼び出されます。
function receiveMessage(event)
{
  // このメッセージの送信者は信頼している者か?
  if (event.origin !== "http://example.com:8080")
    return;

  // event.source は window.opener
  // event.data は "hello there!"

  // 受け取ったメッセージのオリジンを確かめたい場合(どんな場合でもそうするべ
  // きです)、メッセージに返答するための便利なイディオムは event.source 上
  // の postMessage を呼び出し、targetOrigin に event.origin を指定すること
  // です。
  event.source.postMessage("hi there yourself!  the secret response " +
                           "is: rheeeeet!",
                           event.origin);
}

window.addEventListener("message", receiveMessage, false);

注記

任意のウィンドウが、いつでも、ウィンドウの文書の場所にかかわらず、メッセージを送るために、任意の他のウィンドウ上でこのメソッドにアクセスするかもしれません。従って、任意のイベントリスナーはメッセージを受け取る際に、origin あるいは source プロパティを用いて、まず最初にメッセージの送信者の識別情報をチェックしなければなりません。これを軽視することはできません。なぜなら、origin あるいは source プロパティのチェックの失敗はクロスサイトスクリプティング攻撃を可能にするからです。

非同期に配信されるスクリプト(タイムアウト、ユーザーが生成したイベント)のために postMessage の呼び出し元の判別が不可能であるとき、postMessage によって送られるイベントを待ち受けているイベントハンドラは例外を投げます。

postMessage()MessageEvent を、すべての待ち状態の実行コンテキストが終了した後のみ配信するためにスケジューリングします。例えば、 postMessage() がイベントハンドラーから呼び出された場合、 MessageEvent が配信される前に、そのイベントハンドラーが最後まで実行され、同じイベントの残りのハンドラーが実行されます。

配信されるイベントの origin プロパティは呼び出すウィンドウの document.domain の現在の値に影響されません。

IDN ホスト名に限った話ですが、origin プロパティの値が Unicode と Punycode のどちらなのかは一貫していません。ですから、IDN サイトからのメッセージを期待する場合にこのプロパティを用いるときは、互換性を高めるために、IDN と Punycode の両方でチェックしてください。この値は最終的には 一貫して IDN になるはずですが、現在は IDN と Punycode 両方の形式を扱うべきです。

送信元ウィンドウが javascript:data: のURLを持つ場合、origin プロパティの値はその URL を読み込んだスクリプトのオリジンになります。

window.postMessage を拡張機能で使う

window.postMessage は chrome コードで実行される JavaScript で利用可能です(例:拡張内および特権コード)。しかし、配信されるイベントの source プロパティはセキュリティ上の制限から常に null です(他のプロパティは期待された値です)。

コンテンツスクリプトやウェブコンテキストスクリプトは targetOrigin を拡張機能 (バックグラウンドスクリプトやコンテンツスクリプト) と直接通信するために指定することはできません。ウェブやコンテンツのスクリプトは、 window.postMessagetargetOrigin"*" にして使用することで、すべてのリスナーにブロードキャストすることができますが、これは拡張機能がそのようなメッセージのオリジンを特定することができないこと、他のリスナー (制御するべきでないものも含む) が待ち受けしている可能性があるため推奨されません。

コンテンツスクリプトでバックグラウンドスクリプトと通信したい場合は runtime.sendMessage を使うべきです。ウェブコンテキストスクリプトでバックグラウンドスクリプトと通信したい場合はカスタムイベント(ゲストページから覗かれなくない場合など、必要であればランダム生成したイベント名で)を使うことができます。

最後に、 file: URL のページへのメッセージを送るには targetOrigin 引数を "*" にする必要があります。 file:// はセキュリティ上の制限のために用いることはできません、この制限は将来修正されるかもしれません。

仕様書

仕様書 状態 備考
HTML Living Standard
postMessage() の定義
現行の標準

ブラウザーの互換性

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung Internet
postMessageChrome 完全対応 1Edge 完全対応 12Firefox 完全対応 8
補足
完全対応 8
補足
補足 Supports sending File and FileList objects between windows. This is only allowed if the recipient's principal is contained within the sender's principal for security reasons.
完全対応 6
補足
補足 The message parameter is serialized using the structured clone algorithm. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.
未対応 ? — 6
補足
補足 The message parameter must be a string.
IE 完全対応 10
補足
完全対応 10
補足
補足 IE10 had an important limitation: see this article for details.
未対応 8 — 10
補足
補足 Support only for <frame> and <iframe>.
Opera 完全対応 9.5Safari 完全対応 4WebView Android 完全対応 ありChrome Android 完全対応 ありFirefox Android 完全対応 8
補足
完全対応 8
補足
補足 Supports sending File and FileList objects between windows. This is only allowed if the recipient's principal is contained within the sender's principal for security reasons.
完全対応 6
補足
補足 The message parameter is serialized using the structured clone algorithm. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.
未対応 ? — 6
補足
補足 The message parameter must be a string.
Opera Android 完全対応 ありSafari iOS 完全対応 あり
補足
完全対応 あり
補足
補足 For security reasons, to work properly on Safari, construct using document.getElementById('your-frame').contentWindow.
Samsung Internet Android 完全対応 あり
transfer argumentChrome ? Edge 完全対応 12Firefox 完全対応 20IE 完全対応 ありOpera ? Safari ? WebView Android ? Chrome Android ? Firefox Android 完全対応 20Opera Android ? Safari iOS ? Samsung Internet Android ?

凡例

完全対応  
完全対応
実装状況不明  
実装状況不明
実装ノートを参照してください。
実装ノートを参照してください。

関連情報