Avoiding cross-site scripting issues with iframes

At iPaper we often have clients who want to iframe our catalogs as well as interact with these. But when working with iframes, you will run into cross-site scripting limitations if both the parent and child page do not have the same origin. By “same origin”, we mean that these pages have the same protocol and port.

Problem

Now since iPaper catalogs are hosted on their own domain this poses a problem. The page from where the client wishes to iframe a catalog is, of course, hosted somewhere completely different, giving it a completely different origin.

Let’s look at why this is a problem by first seeing what will work followed by where the problem comes in.

Works out of the box

  1. abc.com/test1.htm
  2. abc.com/test2.htm

These 2 pages can iframe each other without ‘same origin’ security errors showing up when trying to communicate between them.

Works out of the box (if properly configured)

  1. abc.com/test1.htm
  2. sub.abc.com/test2.htm

If the first page tries to iframe the second and these try to communicate with each other then you will get a security error. But there is a solution!

Will not work

  1. abc.com/test1.htm
  2. def.com/test2.htm

If the first page here iframes the second and tries to communicate between them, an error will be thrown by the browser since now the same origin policy can not be applied.

Example/Solution

So the last example will not work. And the first example needs everything to be on the same domain. But the example in the middle gives us an opening. By assigning a custom domain to the catalog and having this be a subdomain of the root domain which is iframing it we can actually make communication between them work.

The code below shows 2 files. Now these two files, one hosted on the root domain and the other on a subdomain of this, will not be able to interact if it was not for a special piece of code.

document.domain = ‘abc.com’;

What this does is tell the browser to use the shorter suffix of the current domain for all origin checks. This means that both pages will now use abc.com for their origin check and since these will be the same this check now passes without any problems.

sub.abc.com/test2.htm

<body>

	 <script type="text/javascript">
	 	document.domain = 'abc.com';

	 	var api = {};

	 	window.parent.Init(api);

	 	setTimeout(function () {
	 		if (api.run)
	 			api.run('Rock and roll!');
	 	}, 5000);
	</script>

</body>

abc.com/test1.htm

<body>

	<script type="text/javascript">
			// Communicate with pages not on same sub-domain but only same domain
        	document.domain = 'abc.com';

			// Function which we expose to be called by our 'child' frame
        	function Init(api) {
				
				// Attach function to API object being passed to us by our 'child'
        		api.run = function (msg) {
					
					// Using msg object being passed to us by child
        			document.getElementById('display').value = msg;
        		};
        	}
	</script>

	<div id="display" style="border: solid 1px #FF0000">
		<!-- msg will be inserted here -->
	</div>

	<iframe src="sub.abc.com/test2.html"></iframe>

</body>

The example above has test1.htm iframing test2.htm. On load test2.htm calls the init method of test1.htm allowing this to attach a method which test1.htm can use to write a message within the red box of test2.htm.

As you can see the solution is actually quite simple. By making sure that every page has the same root domain and has document.domain set they can indeed communicate without cross-site scripting issues.

Speak Your Mind

*