Secure Cross-Site (Cross-Domain) Scripting
by Frozen Mountain Software, on January 30, 2009
In the past few months, we have been actively developing WebSync, a product and service that will allow developers to synchronize web content securely across multiple browser sessions. Using a technique known as long-polling or "comet", it enables real-time connections among website users.
Part of our plan is to allow the development community to use our server (in beta) as a hosted serviceto let people understand its advantages and prove its usefulness.
The process of developing a drop-in client-side script that would allow remotely-hosted real-time browser synchronization was not a simple one. In particular, cross-site scripting proved most difficult.
For our application, we needed to be able to:
If cross-site scripting were not completely restricted, we would be able to:
- Create an html page on site A.
- Embed an iframe in that page with a source page from site B.
It is my understanding that future web browsers will allow this for domains where the communication is explicitly allowed. However, until such features are present and widespread, we have to resort to other means.
Our solution is to provide a "double-proxy" whereby both domains host a small proxy file that routes data in and out. We rely on the window.name property to pass data, which can be set on an iframe by a parent, and read internally by the iframe content.
The general process is actually quite simple.
- Page A creates an iframe whose source is page B.
- Page A creates a temporary hidden iframe whose source is proxy B and whose window name is the serialized data.
Here's the catch. In order for proxy B to get a reference to page B, it must search its sibling iframes until it finds a match.
The reverse process is very similar.
- Page B creates a temporary hidden iframe whose source is proxy A, and whose window name is the serialized data.
For proxy A to get a reference to page A, it simply jumps to its grandparent.
There are implementation-specific details (i.e. static/dynamic nature of proxy-invoked functions, deserialization timing, proxy life-cycle/recycling, additional domain verification, etc.), but they detract from the core procedure, and so shall be left to the reader as an exercise ;)
The process is not entirely ideal, as for client applications, it requires the uploading of a proxy/callback file on client servers. It is, however, completely transparent to users, and operates beautifully in modern browsers.