--- title: window.postMessage slug: Web/API/Window/postMessage tags: - API - Cross-origin Communication - DOM - HTML DOM - Method - Reference - Window - postMessage - メソッド translation_of: Web/API/Window/postMessage ---
window.postMessage()
は、 {{domxref("Window")}} オブジェクト間で安全にクロスドメイン通信を可能にするためのメソッドです。例えば、ポップアップとそれを表示したページの間や、iframe とそれが埋め込まれたページの間での通信に使うことができます。
通常、異なった複数のページでのスクリプトはそれらが実行されたページが同じプロトコル、ポート番号、ホストである場合に限りお互いにアクセスすることが可能です ("同一オリジンポリシー" とも呼ばれます)。正しく使用した window.postMessage
はこの制限を安全に回避するための制御された仕組みを提供します。
大まかには、ウィンドウが他のウィンドウへの参照を取得できる場合 ( targetWindow = window.opener
など)、targetWindow.postMessage()
を使って {{domxref("MessageEvent")}} をそのウィンドウ上で配信することができます。受け取ったウィンドウでは必要に応じて自由にイベントを処理することができます。window.postMessage()
に渡された引数 (“message”) はイベントオブジェクトを通して対象のウィンドウに公開されます。
targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
message
targetOrigin
otherWindow
のオリジンを "*"
というリテラル文字列(制限しないことを示します)か URI のいずれかで指定します。もしイベントの配信が予約される時点で、targetWindow
のドキュメントのスキーマ、ホスト名、あるいはポートが targetOrigin
で指定されたものにマッチしない場合、そのイベントは配信されません。3 つすべてがマッチした場合にだけイベントが配信されます。この仕組みはメッセージがどこに送られるかを制御できるようにしています。例えば postMessage
をパスワードを送るために利用する場合、悪意のある第三者によるパスワードの傍受を防ぐため、そのメッセージを受け取るべき受信者のオリジンと一致する URI をこの引数に指定しておくことが非常に重要になります。 送信先ウィンドウのドキュメントがどこに配置されるのかを知っている場合、*
ではなく具体的な targetOrigin
を指定してください。具体的なターゲットを指定しない場合、相手が悪意を持ったサイトであっても、送信したデータが公開されることを意味します。transfer
{{optional_Inline}}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()
は {{domxref("MessageEvent")}} を、すべての待ち状態の実行コンテキストが終了した後のみ配信するためにスケジューリングします。例えば、 postMessage()
がイベントハンドラーから呼び出された場合、 {{domxref("MessageEvent")}} が配信される前に、そのイベントハンドラーが最後まで実行され、同じイベントの残りのハンドラーが実行されます。
配信されるイベントの origin
プロパティは呼び出すウィンドウの document.domain
の現在の値に影響されません。
IDN ホスト名に限った話ですが、origin
プロパティの値が Unicode と Punycode のどちらなのかは一貫していません。ですから、IDN サイトからのメッセージを期待する場合にこのプロパティを用いるときは、互換性を高めるために、IDN と Punycode の両方でチェックしてください。この値は最終的には 一貫して IDN になるはずですが、現在は IDN と Punycode 両方の形式を扱うべきです。
送信元ウィンドウが javascript:
や data:
のURLを持つ場合、origin
プロパティの値はその URL を読み込んだスクリプトのオリジンになります。
window.postMessage
は chrome コードで実行される JavaScript で利用可能です(例:拡張内および特権コード)。しかし、配信されるイベントの source
プロパティはセキュリティ上の制限から常に null
です(他のプロパティは期待された値です)。
コンテンツスクリプトやウェブコンテキストスクリプトは targetOrigin
を拡張機能 (バックグラウンドスクリプトやコンテンツスクリプト) と直接通信するために指定することはできません。ウェブやコンテンツのスクリプトは、 window.postMessage
を targetOrigin
を "*"
にして使用することで、すべてのリスナーにブロードキャストすることができますが、これは拡張機能がそのようなメッセージのオリジンを特定することができないこと、他のリスナー (制御するべきでないものも含む) が待ち受けしている可能性があるため推奨されません。
コンテンツスクリプトでバックグラウンドスクリプトと通信したい場合は runtime.sendMessage を使うべきです。ウェブコンテキストスクリプトでバックグラウンドスクリプトと通信したい場合はカスタムイベント(ゲストページから覗かれなくない場合など、必要であればランダム生成したイベント名で)を使うことができます。
最後に、 file:
URL のページへのメッセージを送るには targetOrigin
引数を "*"
にする必要があります。 file://
はセキュリティ上の制限のために用いることはできません、この制限は将来修正されるかもしれません。
仕様書 | 状態 | 備考 |
---|---|---|
{{SpecName('HTML WHATWG', "web-messaging.html#dom-window-postmessage", "postMessage()")}} | {{Spec2('HTML WHATWG')}} |
{{Compat("api.Window.postMessage")}}