What a pain.
I’m working on an HTML-based course interface that serves up content in an iframe. I had everything working great until I needed to move the content to one domain while hosting the interface on a different domain (kind of a simplified home-brewed CMS approach). BAM! Cross-domain security issues. Course interface dead in the water.
Cross-domain iframe security has been an issue for years and still hasn’t been resolved. Hacks abound, but none are the end-all-be-all solution.
One of the most popular hacks for getting around an iframe’s cross-domain security constraints is the fragment identifier hack. The simple explanation is that you can add data to the end of a page’s URL by using a hash (#
, aka pound sign or octothorpe), just like named anchor elements. (Hashes are preferred over querystrings because querystrings would cause the page to reload, while using a hash doesn’t.) You’d then create a JavaScript function that monitors the URL for changes and evaluates whatever new data is in the ‘fragment.’
For example, the iframe myurl.com/index.html
could have its URL appended to read myurl.com/index.html#somekindofdata
. The parent frame would notice the change and could use conditional code to act on whatever the fragment contains.
The downsides to this approach make it unusable for my e-learning course interface. The biggest downside is that it breaks the browsing history model, rendering the browser’s ‘back’ button practically useless. It also breaks the named anchor functionality, which I use in a number of places. It is limited in scope, requiring all JavaScript to be converted to a string before being added to the URL; this means no native sending/receiving of JavaScript objects, booleans, etc… everything needs to be serialized and deserialized. Which brings me to the last point: this adds to code weight, code complexity, and processing time (especially when using polling to monitor changes to the URL); all three suck are undesirable.
I don’t have a solution I like yet, but I will continue to search and experiment. I was hoping a JavaScript framework like MooTools would have some kind of workaround built-in, but no dice. Other approaches include using Flash hacks and using server-side processing. I can’t use server-side processing since I’m not in control of the primary domain. Flash hacks are a possibility, but I’ve worked hard to ensure this course interface is cross-browser and cross-platform without requiring plugins. *sigh*
Wish me luck, I’ll need it.
Update 11/30/08: I’ve written about the workaround I decided to use; read about the workaround here.
Comments
David Storey wrote on October 24, 2008 at 5:47 am:
This may or may not help you but the JQuery framework has a pretty nifty 'plugin' which uses AJAX to easily recreate iFrame functionality.
http://plugins.jquery.com/project/jframe
Ironically when IE7 came out it broke Authorware's ability to communicate with a SCORM API but this could be fixed by exploiting a bug in IE7 by sticking the content in an iFrame.
Philip Hutchison wrote on October 24, 2008 at 8:57 am:
@david
Thanks for the tip. I use a similar feature in MooTools.The problem for me is that no matter <em>how</em> the iframe is created, it still hits the cross-domain restrictions.
Philip Hutchison wrote on October 24, 2008 at 8:58 am:
And a quick update: I settled on a workaround that uses a dynamically-generated iframe to communicate with the parent frame (a pretty common trick). I'll blog about it soon.
AnobjectN wrote on November 20, 2008 at 8:23 am:
Philip,
I wanted to suggest using JSON formatted text in the hash as that would allow you to pass typed data, objects and functions. I havent tried this myself but you mentioned that you believed the hash was more limited that it would be if you can use JSON there.
One other suggestion: if you can get it so that the host site and the iframe site have the same domain (different sub-domains) then you can make the iframes work as before so long as host site and iframe site have this js statement:
document.domain = "maindomain.com";
The host could be www.maindomain.com and your iframes could be in cmscontrolled.maindomain.com and the iframes would work as if they were on the same domain.
Philip Hutchison wrote on November 20, 2008 at 10:28 am:
Thanks for the suggestions.
JSON could be handy, but it also poses some complications: what if one variable contained a string with reserved characters such as a questionmark (?) or hash (#)? It might wind up confusing the browser. So if you use JSON, you'd also need to character encode the strings to handle special characters.
The same domain approach would be great, but unfortunately, I have to deal with two completely different domains.
This reminds me I need to post my blog explaining what I eventually wound up using. 🙂
AnobjectN wrote on November 20, 2008 at 1:27 pm:
You already have something that works but for others' benefit, there is the proxy page approach. You get your 'foreign' domain data from a local file that gets the remote page using server-side methods that aren't restricted by client-side same-domain restrictions.
John wrote on November 26, 2008 at 2:37 pm:
I'm intrigued to know how you solved this. I'm in a similar situation. I've tried just about every trick in the book to get the various browsers to read an XML file from another domain to no avail. The only browser that seems to allow for any sort of cross-domain read functionality (in IFrames) without any sort of 'hack' is Safari for some reason.
This may or may not help you but the JQuery framework has a pretty nifty ‘plugin’ which uses AJAX to easily recreate iFrame functionality.
http://plugins.jquery.com/project/jframe
Ironically when IE7 came out it broke Authorware’s ability to communicate with a SCORM API but this could be fixed by exploiting a bug in IE7 by sticking the content in an iFrame.
@david
Thanks for the tip. I use a similar feature in MooTools.
The problem for me is that no matter how the iframe is created, it still hits the cross-domain restrictions.
And a quick update: I settled on a workaround that uses a dynamically-generated iframe to communicate with the parent frame (a pretty common trick). I’ll blog about it soon.
Philip,
I wanted to suggest using JSON formatted text in the hash as that would allow you to pass typed data, objects and functions. I havent tried this myself but you mentioned that you believed the hash was more limited that it would be if you can use JSON there.
One other suggestion: if you can get it so that the host site and the iframe site have the same domain (different sub-domains) then you can make the iframes work as before so long as host site and iframe site have this js statement:
document.domain = “maindomain.com”;
The host could be http://www.maindomain.com and your iframes could be in cmscontrolled.maindomain.com and the iframes would work as if they were on the same domain.
Thanks for the suggestions.
JSON could be handy, but it also poses some complications: what if one variable contained a string with reserved characters such as a questionmark (?) or hash (#)? It might wind up confusing the browser. So if you use JSON, you’d also need to character encode the strings to handle special characters.
The same domain approach would be great, but unfortunately, I have to deal with two completely different domains.
This reminds me I need to post my blog explaining what I eventually wound up using. 🙂
You already have something that works but for others’ benefit, there is the proxy page approach. You get your ‘foreign’ domain data from a local file that gets the remote page using server-side methods that aren’t restricted by client-side same-domain restrictions.
I’m intrigued to know how you solved this. I’m in a similar situation. I’ve tried just about every trick in the book to get the various browsers to read an XML file from another domain to no avail. The only browser that seems to allow for any sort of cross-domain read functionality (in IFrames) without any sort of ‘hack’ is Safari for some reason.