Эта статья нуждается в техническом обзоре. Как вы можете помочь.
Наши волонтёры ещё не перевели данную статью на Русский. Присоединяйтесь к нам и помогите закончить эту работу!
The window.postMessage
method safely enables cross-origin communication. Normally, scripts on different pages are allowed to access each other if and only if the pages that executed them are at locations with the same protocol (usually both https
), port number (443
being the default for https
), and host (modulo document.domain being set by both pages to the same value). window.postMessage
provides a controlled mechanism to circumvent this restriction in a way which is secure when properly used.
The window.postMessage
method, when called, causes a MessageEvent
to be dispatched at the target window when any pending script that must be executed completes (e.g., remaining event handlers if window.postMessage
is called from an event handler, previously-set pending timeouts, etc.) The MessageEvent
has the type message
, a data
property which is set to the value of the first argument provided to window.postMessage
, an origin
property corresponding to the origin of the main document in the window calling window.postMessage
at the time window.postMessage
was called, and a source
property which is the window from which window.postMessage
is called. (Other standard properties of events are present with their expected values.)
Syntax
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
- A reference to another window; such a reference may be obtained, for example, using the
contentWindow
property of aniframe
element, the object returned by window.open, or by named or numeric index on window.frames. message
- Data to be sent to the other window.
The data
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. [1] targetOrigin
- Specifies what the origin of
otherWindow
must be for the event to be dispatched, either as the literal string"*"
(indicating no preference) or as a URI. If at the time the event is scheduled to be dispatched the scheme, hostname, or port ofotherWindow
's document does not match that provided intargetOrigin
, the event will not be dispatched; only if all three match will the event be dispatched. This mechanism provides control over where messages are sent; for example, ifpostMessage
was used to transmit a password, it would be absolutely critical that this argument be a URI whose origin is the same as the intended receiver of the message containing the password, to prevent interception of the password by a malicious third party. Always provide a specifictargetOrigin
, not*
, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site. transfer
Optional- Is a sequence of
Transferable
objects that are transferred with the message. The ownership of these objects is given to the destination side and they are no longer usable on the sending side.
The dispatched event
otherWindow
can listen for dispatched messages by executing the following JavaScript:
window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object. if (origin !== "https://example.org:8080") return; // ... }
The properties of the dispatched message are:
data
- The object passed from the other window.
origin
- The origin of the window that sent the message at the time
postMessage
was called. This string is the concatenation of the protocol and "://", the host name if one exists, and ":" followed by a port number if a port is present and differs from the default port for the given protocol. Examples of typical origins arehttps://example.org
(implying port443
),https://example.net
(implying port80
), andhttps://example.com:8080
. Note that this origin is not guaranteed to be the current or future origin of that window, which might have been navigated to a different location sincepostMessage
was called. source
- A reference to the
window
object that sent the message; you can use this to establish two-way communication between two windows with different origins.
Security concerns
If you do not expect to receive messages from other sites, do not add any event listeners for message
events. This is a completely foolproof way to avoid security problems.
If you do expect to receive messages from other sites, always verify the sender's identity using the origin
and possibly source
properties. Any window (including, for example, https://evil.example.com
) can send a message to any other window, and you have no guarantees that an unknown sender will not send malicious messages. Having verified identity, however, you still should always verify the syntax of the received message. Otherwise, a security hole in the site you trusted to send only trusted messages could then open a cross-site scripting hole in your site.
Always specify an exact target origin, not *
, when you use postMessage
to send data to other windows. A malicious site can change the location of the window without your knowledge, and therefore it can intercept the data sent using postMessage
.
Example
/* * In window A's scripts, with A being on <https://example.com:8080>: */ var popup = window.open(...popup details...); // When the popup has fully loaded, if not blocked by a popup blocker: // This does nothing, assuming the window hasn't changed its location. popup.postMessage("The user is 'bob' and the password is 'secret'", "https://secure.example.net"); // This will successfully queue a message to be sent to the popup, assuming // the window hasn't changed its location. popup.postMessage("hello there!", "https://example.org"); function receiveMessage(event) { // Do we trust the sender of this message? (might be // different from what we originally opened, for example). if (event.origin !== "https://example.org") return; // event.source is popup // event.data is "hi there yourself! the secret response is: rheeeeet!" } window.addEventListener("message", receiveMessage, false);
/* * In the popup's scripts, running on <https://example.org>: */ // Called sometime after postMessage is called function receiveMessage(event) { // Do we trust the sender of this message? if (event.origin !== "https://example.com:8080") return; // event.source is window.opener // event.data is "hello there!" // Assuming you've verified the origin of the received message (which // you must do in any case), a convenient idiom for replying to a // message is to call postMessage on event.source and provide // event.origin as the targetOrigin. event.source.postMessage("hi there yourself! the secret response " + "is: rheeeeet!", event.origin); } window.addEventListener("message", receiveMessage, false);
Notes
Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin
and possibly source
properties. This cannot be overstated: Failure to check the origin
and possibly source
properties enables cross-site scripting attacks.
As with any asynchronously-dispatched script (timeouts, user-generated events), it is not possible for the caller of postMessage
to detect when an event handler listening for events sent by postMessage
throws an exception.
The value of the origin
property of the dispatched event is not affected by the current value of document.domain
in the calling window.
For IDN host names only, the value of the origin
property is not consistently Unicode or punycode; for greatest compatibility check for both the IDN and punycode values when using this property if you expect messages from IDN sites. This value will eventually be consistently IDN, but for now you should handle both IDN and punycode forms.
The value of the origin
property when the sending window contains a javascript:
or data:
URL is the origin of the script that loaded the URL.
Using window.postMessage in extensions
window.postMessage
is available to JavaScript running in chrome code (e.g., in extensions and privileged code), but the source
property of the dispatched event is always null
as a security restriction. (The other properties have their expected values.) The targetOrigin
argument for a message sent to a window located at a chrome:
URL is currently misinterpreted such that the only value which will result in a message being sent is "*"
. Since this value is unsafe when the target window can be navigated elsewhere by a malicious site, it is recommended that postMessage
not be used to communicate with chrome:
pages for now; use a different method (such as a query string when the window is opened) to communicate with chrome windows. Lastly, posting a message to a page at a file:
URL currently requires that the targetOrigin
argument be "*"
. file://
cannot be used as a security restriction; this restriction may be modified in the future.
Specifications
Specification | Status | Comment |
---|---|---|
WHATWG HTML Living Standard The definition of 'window.postMessage' in that specification. |
Living Standard | No change from HTML5 Web Messaging |
HTML5 Web Messaging The definition of 'window.postMessage' in that specification. |
Recommendation | Initial definition. |
Browser compatibility
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|
Basic support | 1.0 | 6.0 (6.0)[1] 8.0 (8.0)[2] |
8.0[3] 10.0[4] |
9.5 | 4.0 |
transfer argument |
? | 20.0 (20.0) | Not supported | ? | ? |
Feature | Android | Firefox Mobile (Gecko) | IE Phone | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|
Basic support | (Yes) | 6.0 (6.0)[1] 8.0 (8.0)[2] |
(Yes) | (Yes) | (Yes) |
transfer argument |
? | 20.0 (20.0) | Not supported | ? | ? |
[1] Prior to Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3), the message
parameter must be a string. Starting in Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3), 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.
[2] Gecko 8.0 introduced support for 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.
[3] IE8 and IE9 only support it for <frame>
and <iframe>
.
[4] IE10 has important limitations: see this article for details.