Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.
While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.
When a script invokes the postMessage(message) method on a Window object, the user agent must create an
event that uses the MessageEvent
interface, with the event name message, which bubbles, is cancelable, and has
no default action. The data attribute must be set to the value passed as
the message argument to the postMessage() method, the domain
attribute must be set to the domain of the document that the script that
invoked the methods is associated with, the uri attribute must be
set to the URI of that document, and the source
attribute must be set to the Window
object of the default view of the browsing context with which that
document is associated.
Define 'domain' more exactly -- IDN vs no IDN, absence of ports, effect of window.document.domain on its value, etc
The event must then be dispatched at the Document object
that is the active document of the Window object on which the method was invoked.
The postMessage() method must only return once
the event dispatch has been completely processed by the target document
(i.e. all three of the capture, target, and bubble phases have been done,
and event listeners have been executed as appropriate).
Authors should check the domain
attribute to ensure that messages are only accepted from domains that they
expect to receive messages from. Otherwise, bugs in the author's message
handling code could be exploited by hostile sites.
For example, if document A contains an object element that contains document B, and
script in document A calls postMessage() on document B, then a
message event will be fired on that element, marked as originating from
document A. The script in document A might look like:
var o = document.getElementsByTagName('object')[0];
o.contentWindow.postMessage('Hello world');
To register an event handler for incoming events, the script would use
addEventListener() (or similar mechanisms). For
example, the script in document B might look like:
document.addEventListener('message', receiver, false);
function receiver(e) {
if (e.domain == 'example.com') {
if (e.data == 'Hello world') {
e.source.postMessage('Hello');
} else {
alert(e.data);
}
}
}
This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.
The integrity of this API is based on the inability for
scripts of one origin to post arbitrary events (using dispatchEvent() or otherwise) to objects in other origins.
Implementors are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.