Developer tips

The iframe cross-domain policy problem

By January 24, 2011 12 Comments

If you are a front-end developer that need to use a cross-domain iframe, you know pain. You could write a nice bit of code and get it working on firefox but it would crash on IE. You would think that would be easy – facebook, twitter and all the others cool kids are doing it! Well, not quite.

Here at Cakemail we are currently building a platform that will enable our users to create forms and embed them in their website directly (think an email list subscription form). So basically, we needed to have javascript control in the parent and in the child.

We had 2 problems to solve based on embedding. One was to change the iframe height dynamically (no way in hell were we going to save the iframe height in a database). And sometimes, depending on what functionality our users embedded in their website, we needed to actually redirect the parent page.

Why it is so hard?

Security: I’m sure I don’t really have to tell you what an intruder could do to your website if it had access to your document. It could bind itself to your login process and just get all your users email/password, redirect your website, etc. This is why implementing a cross-domain communication is not to be taken lightly.

Even if you do it right, you have to think about what could happen if your embedded script was compromised. Especially if you embed that script in other websites that are not yours!

Accessing to a parent window and document

Accessing to a parent document is really simple when you are on the same domain, you do a quick window.opener.MyParentFunction(), and you’re done.

However doing this cross-domain? Not so easy. You’ll get something along the line of: Child document does not have the right to access parent document. In fact there is a lot of documentation on the web about how to achieve it, but the problem is that it is often outdated, with solutions that often only works in a couples of browsers.

Doing it the old way: An iframe in an iframe in an iframe

A clever idea that popped up some time ago – embedding an iframe in your child window that’s on the same domain that your parent window. It works, most of the time, but there are variants to this technique where some work and some don’t. Some variants involve the url using a hash to pass data (#), which is really bad if you want to pass lots of data, and also makes annoying noise in IE and a horrible browsing history.

But remember that this is still a hack. You’re bypassing the protection using a somewhat clever idea, and there is always a chance that it will stop working one day with a browser update.

A nice resource for the old hacks

This website really gets into detail on how to make the iframe hacks work. It’s really useful if you want to understand in details how the iframe cross-domain policy works.

The HTML5 way

Ahhh HTML5, the savior of all our problems – right? For the cross-domain issue, HTML5 implemented a nice new javascript method, postmessage.

window.postmessage was specifically implemented to resolve the cross domain policy problem, safely (well as safe as possible..). Here’s what a communication would look like:

It comes with 2 options to make it as secure as possible, origin and source. Origin being the message domain origin and source being a reference to the window object.

What about ie?

Postmessage is in ie8, however it’s not in ie7 & ie6 (obviously). If you need to support those browsers you will have to rely on another technique.

You can get a really complete description and examples of postmessage on the Mozilla javascript documentation website.

As usual, for a good cross-browser solution we need to compromise

As with a lot of things with the DOM, the best way to do it cross browser is to use the best solution possible, and rely on hacks for older browsers.

Fortunately, that is exactly what easyXDM did for you. This library is (or has been) used by a lot of websites, including Twitter and Disqus! It gives you a nice api that works everywhere. Let’s have a look:

 

What about IE, how does easyXDM work its magic?

You would think that easyXDM use the simple iframes trick to work in ie7 & ie6, but in fact it use a much more clever hack. It use an ie only protocol (some kind of vbscript) that makes cross-domain communication possible, the NixTransport.

“This implementation therefore wraps the JavaScript objects used inside a VBScript class. Since VBScript objects are passed in JavaScript as a COM wrapper (like DOM objects), they are thus opaque to JavaScript (except for the interface they expose). This therefore provides a safe method of transport. Initially based on FrameElementTransport which shares some similarities to this method. “

Limitations

One clear limitation I noticed using this library is that loading a children window without being embedded from the parent make easyXDM throw a js error. There are ways on the forum to correct this using a third window but it’s not really convenient, I also did some tests with the onReady option. It seemed to work at first, but it sometimes still throws an error anyway.

For what it’s worth, it is still the most powerful library I found out there, I sent a message of 1mb and it still got through, even in IE7, and its really fast.

That’s it!

Hope this can help you get all your cross-domain communication going!

This piece was written by Cedric Dugas, CakeMail’s Interface Developer. You can follow Cedric on twitter @posabsolute.

Please wait...

Author Cedric Dugas

More posts by Cedric Dugas

Join the discussion 12 Comments

  • Thanks for mentioning easyXDM – even though it is as you say the most powerful library out there, many are still advocating bad practices for XDM.

    If you have any issues or ideas, please do bring them to my attention using the mail list or by creating an issue – I aim for it to be as good as it possible can be 🙂

    Regarding the `onRead` feature – could you report the nature of this issue? Was it directly related to when you navigated the inner frame (which is not supported, and never will be due to reasons stated numerous times on the mail list)?

    Please wait...
  • cedric says:

    Hey Øyvind,

    Yeah, it was from it directly related to when you navigated the inner frame. At first I thought it worked for a while, I might be mistaken.

    Beside this we currently do not have any issue, its rocking! 😉

    Please wait...
  • easyXDM sounds very useful – thanks for the reference.

    It’s worth noting, though, that if you simply need to navigate a parent or other window to a new URL, you can do that without any special tricks. Just assign into parent.location or whatever.location as you normally would. There’s no cross-domain restriction on *writing* to a window.location property, only on *reading* from it.

    This is how the popular fragement identifier trick works – one window writes to the hash portion of another window’s URL (which it can do cross-domain) and the other window uses a timer to watch for hash changes.

    Please wait...
  • Chad says:

    Grat timing on this post. I needed to look into this in the next few days. Thanks!

    Please wait...
  • Dr_rOot says:

    Thx 4 share!

    Please wait...
  • […] The iFrame cross-domain policy problem and an HTML5 solution. […]

    Please wait...
  • Yinch says:

    Hi Cedric, thanks for the article… I have been reading cross-domain issues for a few weeks, most of the solution involves that we change the parent domain scripts, but in the case of Facebook, parent script is from Facebook, we have no access to it, and it internally creates the iframe for our FB app, so all the solution can not be used, am I wrong here? thanks.

    Please wait...
  • Ken Deeds says:

    One note if the page you are opening in the iframe is using PHP (could be done with other dynamic lanaguages) when the page first opens if your server has $_SERVER[‘HTTP_REFERRER’] available you can use this in the page being opened to grab the full url and query string of the parent page. Then set this to a variable in the page you opened in the iframe and you have your parent URL.

    Please wait...
  • I do not understand the point 3.

    How could you, inside a remote iframe, load your local iframe ?

    I mean, its forbiden ?

    I understand all the steps excepted this one.

    Please wait...