Secure Cross Domain iFrame Communication

2012-04-09 Update: Porthole has been updated. Read more

The world of web development is full of limitations and workarounds to overcome those limitations.

IFrames are commonly used as a secure way to embed content from another site. Unfortunately it’s often not enough to have the content live within the frame. A common use case is the display of so called rich media ads. In these kind of ads, the creative within the ad is meant to expand beyond the boundary of the iFrame rectangle. In order to do so, it needs the cooperation of its parent page.

The "state of the art" method to achieve this is via a mechanism known as iFrame busting. Unfortunately, this technique greatly compromises the security offered by iFrames because it enables the content in the iFrame to have access to every objects in the parent page context. As such, any ad content can have access to everything the parent page has access to (reading cookies, form fields, etc.), bypassing the same origin security policy. This overkill solution is being accepted as the de facto standard by everyone in the online ad industry. This needs to stop.

For the most part, the communication between parent and iFrame can be narrowed down to a few messages (maximize me, shrink me, color me pink, etc.). By enabling a post/subscribe message type of system between the parent and the iFrame, most of the needs can be covered without having to give the iFrame carte blanche to everything in the parent DOM.

With HTML 5, a safe mechanism to post messages between windows was introduced ( window.postMessage). Until the adoption of HTML 5 compliant browsers is wide enough, we're left using other techniques to achieve similar results.

Such communication techniques have been well described by Michael Mahemoff in his post about Cross-Domain Communication with IFrames. It even has been further enhanced by Piers Lawson in his post about Another Cross Domain iFrame Communication Technique.

These posts have inspired the creation of Porthole, a small Javascript library that makes it easy to incorporate this method into existing pages.

Porthole relies on hidden iFrames (later referred to a as proxy) to exchange information. The caller sets a url fragment with the message to pass. The proxy by virtue of being served from the same origin as the callee, invokes a callback method with an event object that contains the message read from the url fragment. The message signaling mechanism is based on a resize event.

Simplified view of iFrame content and iFrame proxies.

A proxy iFrame is needed for each direction of message passing (e.g. from Parent to iFrame and/or iFrame to Parent).

Calling sequence for sending and receiving a message.

Usage

Include the Javascript.

<script type="text/javascript" src="porthole.js"></script>

Create your content iFrame. This is where the guest content lives. Make sure to give it a name.

<iframe id="guestFrame" name="guestFrame" src="http://other-domain.com/">
</iframe>

Define an event handler if you want to receive messages.

function onMessage(messageEvent) {  
    /*
   messageEvent.origin: Protocol and domain origin of the message
   messageEvent.data: Message itself
   messageEvent.source: Window proxy object, useful to post a response 
   */
}

Create a window proxy object on the main page.

var windowProxy;
window.onload=function(){ 
    // Create a proxy window to send to and receive 
    // messages from the iFrame
    windowProxy = new Porthole.WindowProxy(
        'http://other-domain.com/proxy.html', 'guestFrame');

    // Register an event handler to receive messages;
    windowProxy.addEventListener(onMessage);
};

Create a window proxy object in the iFrame.

var windowProxy;
window.onload=function(){ 
    // Create a proxy window to send to and receive 
    // messages from the parent
    windowProxy = new Porthole.WindowProxy(
        'http://parent-domain.com/proxy.html');

    // Register an event handler to receive messages;
    windowProxy.addEventListener(function(event) { 
        // handle event
    });
};

Send a message.

windowProxy.postMessage('supersizeme');

Note that if you have multiple iFrames, you can create as many WindowProxy objects as needed.

Compatibility

The library has been tested with IE 7-8, Safari 5, Firefox 3.6 and Google Chrome 6.0

Demo

See it in action at http://sandbox.ternarylabs.com/porthole/

Source

Download or fork from Github: https://github.com/ternarylabs/porthole/

Talk Back