postMessage API Changes

It’s been a little while since I last wrote about Cross-Window Messaging in Firefox 3 using postMessage and since that time it’s since a few API updates.

Specifically the postMessage API has become much simpler and has stronger security brought into mind.

If you’re unfamiliar with postMessage here’s a quick re-cap: It’s a way to communicate simple string-based messages across browser windows (this includes frames, iframes, and popups). It’s a part of HTML 5 specification and is included in Firefox 3, Internet Explorer 8, WebKit Nightlies, and Opera 9.5.

Here’s the revised process works using the final postMessage API (currently only works in Firefox 3):

Sending

Sending is still done by calling the postMessage method on a window object. The one addition is that an extra targetOrigin argument is now required. This argument allows you to specify the exact origin that you’re expecting this message to reach (this can help prevent malicious attempts to redirect the contents of frames to intercepting pages).

It’s highly recommended that you provide an origin, but if you don’t wish to you can specify “*” instead (which will work for any origin).

Demo: https://johnresig.com/apps/message/

<iframe src="http://dev.jquery.com/~john/message/" id="iframe"></iframe>
<form id="form">
  <input type="text" id="msg" value="Message to send"/>
  <input type="submit"/>
</form>
<script>
window.onload = function(){
        var win = document.getElementById("iframe").contentWindow;
        document.getElementById("form").onsubmit = function(e){
                win.postMessage(
                        document.getElementById("msg").value,
                        "http://dev.jquery.com"
                );
                e.preventDefault();
        };
};
</script>

Receiving

The primary change to receiving is that you must now listen for the incoming event on the window object, instead of the document. This is a smart API change (keeping document/window straight would’ve surely caused implementation problems).

Additionally, in the incoming event object, there use to be a number of properties made available for determining the origin of the request. Now, however, there is only a single property: event.origin. This property contains the base origin from which the request is coming.

For example in the above demo the full URL is “https://johnresig.com/apps/message/” but the event.origin is just “https://johnresig.com”. It’s highly recommended that you verify the incoming origin of the request in order to prevent any malicious attempts to inject data.

Additionally, even though it’s not done below, it’s important to do some validation on the incoming message contents. It’s entirely possible that the origin page may have been compromised so you’ll need to take that into consideration.

Demo: http://dev.jquery.com/~john/message/ (Use the above demo to see this page in action)

<b>This iframe is located on dev.jquery.com</b>
<div id="test">Send me a message!</div>
<script>
window.addEventListener("message", function(e){
        if ( e.origin !== "https://johnresig.com" )
                return;

        document.getElementById("test").textContent = e.origin + " said: " + e.data;
}, false);
</script>

I’m pleased with these changes and I’m glad that there were able to make it in to Firefox 3 in time. I hope we see some more implementation convergence here as it would be really good to have all four browsers with an HTML 5 feature in it.

Posted: May 22nd, 2008


Subscribe for email updates

7 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.