window.name Transport

By on July 22, 2008 12:04 am

The window.name transport is a new technique for secure cross-domain browser based data transfer, and can be utilized for creating secure mashups with untrusted sources. window.name is implemented in Dojo in the new dojox.io.windowName module, and it is very easy to make web services available through the window.name protocol. window.name works by loading a cross-domain HTML file in an iframe. The HTML file then sets its window.name to the string content that should be delivered to the requester. The requester can then retrieve the window.name value as the response. The requested resource never has access to the requester’s environment (JavaScript variables, cookies, and DOM).

Dojo API

To use the window.name transport, you can use dojox.io.windowName‘s single function, send, with an API very similar to dojo.xhr:

dojox.io.windowName.send(method, args);

The method parameter can be GET or POST. The args parameter is an object that provides the target URL and other information per the Dojo ioArgs API. When you call dojox.io.windowName.send, it will send the specified request and return a dojo.Deferred object, which you can listen to for the response. For example:

var deferred = dojox.io.windowName.send("GET", {url:"http://somesite.com/resource"});
deferred.addCallback(function(result){
  alert("The request returned " + result);
});

Making Web Services Available with window.name

In order to implement window.name with web services (REST or RPC), the server should simply look for requests that include a parameter windowname. If the windowname parameter is included, the server should respond to the request with an HTML document that sets its window.name to the string that is to be delivered to the client. For example, if a client makes a window.name request like:

http://othersite.com/greeting?windowname=true

And if the server wants to respond to the client with Hello, it should return an html page:




The value returned to the client will be Hello. One can easily transfer JSON data as well:




The client will than receive the JSON data as a string which can then be parsed with a JSON parser like dojo.fromJson. On the client side, it is highly recommended you use a JSON or secure JavaScript validator if you want to prevent arbitrary code execution and unrestrained access to your environment from the target web service data. To securely parse the JSON, you can test the JSON with the dojox.secure.capability validator prior to calling fromJson:

var deferred = dojox.io.windowName.send("GET", {url:"http://somesite.com/resource"});
deferred.addCallback(function(result){
  // capability.validate will throw an error 
  // if there is unsafe script code in the JSON
  dojox.secure.capability.validate(result,[],{});
  console.log("received object", dojo.fromJson(result));
});

Writing extensive multi-line JSON objects in a quoted string can be rather difficult and error-prone if you are manually creating resources. You can use this template HTML to easily create JSON data that will be delivered as a JSON string without having to manually escape the JSON as a string:




Likewise, if you want to deliver HTML/XML data, here is a template for doing so without manually putting all the data in a string:



some html/xml-styledata

This module has been tested on Firefox 2 and 3, Safari 3, IE 6 and 7, and Opera 9. You can see a simple test/demo page that loads data using the window.name protocol. By default, this demo loads data from our Persevere server, which now supports this protocol.

Benefits

This technique has several advantages over other cross-domain transports:

  • It is secure, JSONP is not. That is, it is as secure as other frame based secure transports like fragment identifier messaging (FIM), and Subspace. (I)Frames also have their own security issues because frames can change other frames locations, but that is quite a different security exploit, and generally far less serious.
  • It is much faster than FIM, because it doesn’t have to deal with small packet size of a fragment identifier, and it doesn’t have as many “machine gun” sound effects on IE. It is also faster than Subspace. Subspace requires two iframes and two local HTML files to be loaded to do a request. window.name only requires one iframe and one local file.
  • It is simpler and more secure than Subspace and FIM. FIM is somewhat complicated, and Subspace is very complicated. Subspace also has a number of extra restrictions and setup requirements, like declaring all of the target hosts in advance and having DNS entries for a number of different particular hosts. window.name is very simple and easy to use.
  • It does not require any plugins (like Flash) or alternate technologies (like Java).

How does it work?

windowname.png Of course you can use the new windowName module without understanding how it works, but since this is a tool for protecting against miscreant web services, you may wish to understand how it provides protection. name is a property of the global/window object in the browser environment, and the value of the name property remains the same as new pages are navigated for the frame. By loading a resource in an iframe where the target page will set the name property for its frame, this name property value can be retrieved to access the information sent by the web service. The name property is only accessible for frames that are in the same domain. This means that Dojo must navigate the frame back to the origin domain after the remote web service page has been loaded, in order to access the name property. This same-origin policy also protects against other frames from accessing the name property while Dojo is retrieving the value. Once the name property is retrieved, the frame is destroyed.

At the top level, the name property is not secure, any information put in the name property is available for all subsequent pages. However, the windowName module always loads resources in an iframe. The iframe is destroyed once the data is retrieved, or when you navigate to a new page at the top level, so other pages never have access to the window.name property.

The principle vector of attack is for other frames to attempt to access the loading frame and navigate that frame to their own domain in order to access the name property (using the same technique that Dojo does). However, navigating frames that are not child or parent frames is not permitted in most browsers, and therefore the third party frames are blocked from this action by the browser. Only the main frame that is loading the resources can access this information. Unfortunately, Firefox 2 does not block this action. Consequently, the windowName module uses a set of three nested frames, where 1st frame blocks all frame traversal to the 2nd frame using dynamically installed getters that return null. This means that third party frames can never traverse the frames to get a reference to the 2nd or 3rd frames, and consequently can never induce navigation of the target frame (the 3rd frame) in order to access the name property. Same-origin security prevents the third party frame from removing the installed getter that protects access to the inner frames as well. These measures protect against attacks and ensure that data can be delivered securely.

The idea for the window.name transport is based Thomas Franke‘s library for doing session variables with window.name, but this obviously has a completely different goal.

Cross Domain Builds

If you are using Dojo from a CDN or a cross domain build, you will need to set dojo.config.dojoCallbackUrl (which can be set through the djConfig attribute in the dojo.js script tag) to the URL of a blank.html on your server.

Conclusion

The next generation of browsers will most likely include native capabilities for securely accessing resources from other sites, however it is extremely valuable to have a safe, efficient means for loading data from other domains with current browsers, in order to build secure mashups. The window.name transport provides an efficient secure mechanism for loading data and can play an important role as a foundation for client-side mashups for current and legacy browser technology. The new Dojo windowName module is an easy to use tool for leveraging this transport, and handles the cross-browser issues and protects against the different attack vectors so you can safely utilize this protocol. The Dojo windowName module is available in nightly Dojo builds, and will be available with Dojo 1.2.

Comments

  • Pingback: Ajaxian » window.name meet dojox.io.windowName()

  • Pingback: Faire de l'AJAX sans restrictions de domaine , Kévin Gosse()

  • Kirs,
    Great work as usual. I’ve been thinking about using this technique for Jabbify (http://jabbify.com) and adding something to JavaScriptMVC. Currently, we support REST based JSONP. I’ve got it able to do writes by breaking up the message into small chunks.
    Window.name would allow much bigger chunks, and security. But before I make the switch, I have a few questions about your implementation.

    Are you basically creating an iframe, and then polling for window.name to change? Or is there another way to know when the iframe has loaded.

    Should/do you remove window.name on unload to prevent other pages from getting it?

    Should/do you remove the iframe when you are done with it? Or do you just keep using the same one?

    Thanks for your help,

    Justin

  • I presume that dojo.fromJson does not use eval. Seems to me that you can get either security or speed using window.name, but not both. Using eval, you can get the speed of XHR with the cross site feature of JSONP, but using a native JavaScript JSON parser instead of eval you would get cross-siteness and a modicum of security. I think we need performance metrics. It’s a very clever epiphany in any case.

  • dojo.fromJson does use eval, which is why it is not safe to use dojo.fromJson without doing JSON validation first. I will cover that more in the next blog post on security. And you are right that performance metrics would be helpful as well.

  • Pingback: window.name transport - Code Candies()

  • Cool idea guys, you just solved a pressing problem. I snooped your implementation and implemented it in GWT, see here: http://timepedia.blogspot.com/2008/07/cross-domain-formpanel-submissions-in.html

    I adopted your URL convention (windowname=true) for interoperability purposes. It would be nice if, like JSONP, this convention or something like it gets standardized.

    -Ray

  • Pingback: The Punch Barrel / window.name Transport()

  • Pingback: Cross-Domain Transport with Window.Name | Danny Thorpe()

  • Pingback: SitePen Blog » Cross-Site XHR Plugin Registry()

  • Pingback: SitePen Blog » Secure Mashups with dojox.secure()

  • Kris,
    I’m amazed that you are building a form and then submitting it!

    I’m sure this is naive, but would it be possible to make the frame load a page, check window.name, and then do an XHR request? When the request comes back, it updates window.name.

    I guess you would lose the onload functionality and would have to resort to polling. Is this the only reason why? Thanks!

  • I guess performance would suffer too.

  • @Justin: The latest version (in SVN/nightlies) supports setting the window.name property asynchronously. It does this in “authorization mode” where you provide an authorization element so the iframe can interact with the user before handing over information the requesting page. Once the window.name variable is set the target page is responsible for navigating back to a return URL. You could also use this async/auth mode for doing an XHR request if you wanted. I will probably do another post explaining the async/auth functionality more, but it is based on Neil’s post http://www.sitepen.com/blog/2008/07/30/protected-cross-domain-authentication-with-javascript/.

  • Kris,
    Thanks for the reply. I understand how it works. I’ve made a non-dojo version in http://tinyurl.com/5pwk8c.

    I am more wondering if there are other ways of doing it. I’m planning on using it for a Comet request (for http://jabbify.com). But, during the log poll, the mouse shows a waiting hourglass.

    I need to get rid of that hourglass.

  • Sorry, that link is

    http://tinyurl.com/5pwk8c

  • Also, make sure your content type is text/html. I had mine at text/plain and the browser will put the form results in a tag inside the hidden iframe. This prevents the script tag from executing.

  • Ian

    The problem with this technique is that if you use it with IE, redirecting the iframe causes the click sound to fire. Overusing it will make the page sound like firecrackers are going off. I think it still has uses however if the cross domain requests are linked to actual clicks made by the user. I wrote a Jquery version based on the dojo one but it uses one iframe instead of many.

  • @Ian:
    This is an issue, but in contrast to fragment identifier messaging where a click occurs for each ~2K packet, the windowName module is much quieter.
    That is great to hear you built a jquery one, do you have a URL for it? I am curious what you mean when you said your impl only uses one iframe? dojox.io.windowName only uses one iframe, except in the case of FF2 where it must use nested iframes in order to prevent frame-to-frame messaging theft.

  • Pingback: SitePen Blog » Protected Cross Domain Access with Dojo’s windowName()

  • Menon

    Hi
    I am relatively new to Javascript and dojo.

    I am trying to do cross-domain communication with somewhat large data sets. When using the cross frame framework at http://www.julienlecomte.net/blog/2007/11/31/, I ran into the IE limitation of the length of message (around 4K.) I am now trying to find out a way to overcome this in a browser-independent fashion. My requirement is as follows:
    1. The main page has an iframe that points to a different domain.
    2. I want to send a message to the iframe (the message should be received by a Javascript method hosted within the iframe.)
    3. The iframe then does something and can send another message that is intercepted by the Javascript code running in the main page.

    These messages can be larger than 4K but should be less than
    1M.

    I tried to use the dojo 1.1.1 proxy method in the dojox but I am unable to run the example in the “tests” directory provided in the code (I believe I did follow the instructions on modifying the files.)

    I am wondering if window.name transport can be used. If so, is the code available right now since dojo 1.2 does not seem to have been released as yet?

  • @Menon: Currently the window.name transport is only designed for “loading” data from other domains; it hasn’t be adapted for full cross-frame messaging because we change the frame back to the original domain in order to access the window.name value, and this effectively “destroys” the child frame once the data is loaded. We are considering adding a cross-frame messaging system in the future using this technique (with nested iframes).
    If you only need to send a single message and receive a single message before destroying the child, this may still be viable with the new Dojo module. You can download the Dojo nightlies (with the windowName module) at http://archive.dojotoolkit.org/nightly/.

  • Pingback: Comet Daily » Blog Archive » Expanding Cross-Site Comet Options()

  • Pingback: SitePen Blog » Security in Ajax()

  • JP

    I don’t understand how this protects against untrusted sources. You would need access to the service in order to make the responses implement the window.name=. If you have access to the server code, it’s pretty much going to be trusted then, isn’t it? Am I missing something?

  • @JP: Parties can independently implement the window.name protocol. I have implemented window.name for http://persevere.sitepen.com/, but that doesn’t mean you trust that site, however you can still access the site from a web page without trusting it.

  • fry

    I’ve ported this to jQuery as a plugin and added the possibility to send data that includes submit, target, method and action values. You can check the code at http://friedcellcollective.net/outbreak/jsjquerywindownameplugin/.

  • john

    Has this been tested on safari 3?
    i get

    Unsafe JavaScript attempt to access frame with URL http://skylined.org/~fry/js/jQuery.windowName/test.php from frame with URL http://friedcellcollective.net/js/jQuery.windowName/test.html. Domains, protocols and ports must match.

    when trying the demo page.

  • @john: I assume you are talking about the jQuery version, which may not work Safari 3. The Dojo version that I wrote has been tested and does work on Safari 3.

  • Pingback: SitePen Blog » When to Use Persevere: a Comparison with CouchDB and Others()

  • quickredfox

    Kris Zyp, I now love you!

  • Grant A

    Sorry pal – looks like a giant hack to me. The window.name property was never designed for such use, and I can see this being parsed by browsers in the future to prevent hacks like this.

  • Mic

    I made some testing with window.name and have one worry about cookie sharing.

    Imagine you use mashup.com, and unfortunately call, by the iframe technique, a service from pirate.net
    pirate.net injects a script within the iframe HTML.
    pirate.net knows some services that are available from mashup.com. ie: myContacts.com

    If the user of mashup.com has still a valid cookie for myContacts.com(either a “remember me” or another tab is still open on the myContacts.com site).
    This cookie will be sent automatically with any request to myContacts.com. ie: get_contact_list

    pirate.net can then callback and collect this information and sent it back to his site.
    And all this is possible before the onload event fire.

    This happen in FF and Safari as cookies are shared.
    Opera seems to protect them. And IE doesn’t seem to wait enough for the second call to take place.
    Please tell me I’m wrong somewhere :-/

  • @Mic: I am not certain what you mean by “callback and collect this information”, but if you mean making a request to myContacts.com via JSONP or window.name from the pirate.net frame/page leveraging existing cookies, than it sounds like you are just describing a standards CSRF attack. If myContacts.com has CSRF vulnerabilities, pirate.net can attack myContacts.com anytime pirate.net is loaded in the browser at all, the window.name mechanism doesn’t create any new vulnerabilities. You can see http://www.sitepen.com/blog/2008/09/25/security-in-ajax/ for more information about defending yourself against CSRF.

    Let me know if you had something else in mind.

  • Pingback: Sandbox Your Cross Domain JSONP To Improve Mashup Security | BeeBuzz()

  • Mic

    You’re right that’s CSRF. Nothing new here ;)
    We made a variation of the window.name trick described in our blog today http://beebole.com/blog/general/sandbox-your-cross-domain-jsonp-to-improve-mashup-security/
    If you have any comment or feedback, we would be very happy to hear it from you.
    Thanks a bunch for the trick.

  • @Mic: Great work, this is an excellent idea, and helps deal with the primary challenge of window.name, consuming existing services.

  • Thanks Kris for a brilliant solution. One of the coolest things I’ve seen in a long time.

    Worked an almost identical implementation into my own library that I’m working on and it’s been performing consistently for some time.

    Recently however, I noticed a strange bug in Safari where window.name returns something like: “<!–framePath //–>”.

    On investigating it turns out that my backend API was setting window.name to the value of a resource representation (which happened to be an empty array), except that the app had just made an earlier request to another resource which had also responded with an empty array.

    The problem here is that Safari doesn’t allow duplicate window.names. Trying to set window.name to something which is already the window.name for another frame causes Safari to generate it’s own random window.name, hence the “<!–framePath //–>”.

    See: http://markmail.org/message/3p5ibqhdrppa2bc6#query:framePath%20safari+page:1+mid:aps57htayykgzya5+state:results for more details on this.

    A possible fix then, is to make sure the backend API adds a timestamp to the window.name object returned to ensure uniqueness.

  • from Michel:
    > One question: If the foreign server can return
    > > window.name={jasonString} then it can return
    > >
    > > var x = { jsonString }
    > >
    > > then all browsers I know of, will allow
    > > document.write(‘ > src=”http://www.foreignserver.com/requestJson.ext?parms=’+escape(parms)+'”>’)
    > > window.onload=function() {alert(eval(x))}
    > >
    @Michel:
    I assume you mean running this script (doing the document.write) from
    the caller/parent window, on a freshly created iframe (or directly in
    the caller window). However, if the caller created the iframe without
    a foreign source (src attribute), it would inherit the same origin
    domain as the caller (even though it is loading a script from a
    different server). Consequently, the loaded script (from
    foreignserver.com) would be able to navigate to the parent frame and
    access/modify the JavaScript environment of the caller. The main point
    of the window.name mechanism is to provide protection against these
    types of vulnerabilities.

  • Missed this one until now!

  • I was too trigger happy with the submit button there ;-) Just wanted to say: Nice work!

  • We were using crossdomain.xml as our local resource, and as our recommended local resource for clients, since it’s related, can be served with long-lived caching headers, and is prevalent.

    crossdomain.xml worked fine for our application. When served by an ASP server however, Internet Explorer 6 & 7 fail to call the iframe onload event. It appears to be caused by Content-Type. Serving crossdomain.xml as “application/xml” works in IE 6 & 7. Serving crossdomain.xml as “text/xml” does not.

    Secondly, we found that robots.txt worked out of the box in terms of mime type. Thirdly, pointing to a non-existent local resource (favicon.ico or robots.txt) which generates a 404 will also work.

  • cosjav

    Hi Kris,
    I’m trying to use this windowName transport that you have developed but I’m having a couple of problems:

    * Firefox seems to hit the server twice for every dojox.io.windowName.send() call. Is there any way around this or am I setting it up wrong?

    * I tried loading the dojo Javascript libraries from a different domain than my local one but when I invoke the windowName.send() function but it seems to try and load the resources/blank.html on the different domain and there is no result returned in the callback method. I need to host all javascript on this other server so that the local server is not responsible for maintaining it. The code that fails is:

    However if the code above resides on the ‘home.exetel.com.au’ domain then it works fine (this is shown at http://home.exetel.com.au/cosjav/test.html.

    Thanks.

  • cosjav

    Darn.. the code didnt come out.. But you can do a view source on http://home.exetel.com.au/cosjav/test.html and that is the code..

  • @cosjav:
    * Could the issue with double requests be due to Firebug? When I load your page, I only see one window.name request show up in Firebug, but I know sometimes when you view the body of a request in Firebug, it will trigger another request to the same URL.
    * For cross-domain builds, you need to set dojo.config.dojoCallbackUrl (which can be set through the djConfig attribute in the dojo.js script tag) to the URL of a blank.html on your server.

  • Pingback: Cross-Site XHR Plugin Registry « LocalLab : Foire aux Infos()

  • Pingback: Getting Started With Pintura | SitePen Blog()

  • Fahim Akhter

    But what if I wanted to do the same thing with a flash setup instead of Ajax ?

  • @Fahim: There is a flash/JS bridge for cross-origin communication: http://flxhr.flensed.com/

  • Pingback: Pintura JSGI Modules | SitePen Blog()

  • Pingback: javascript使用window.name解决跨域问题 | prototype 跨域()

  • Pingback: 跨域通信window.name Transport « 黑板报 – 赛 唐(Cytang.com)()

  • sky

    Kris, any plans to investigate the activex hack to quiet down window.name for IE?

    http://infrequently.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/

  • @sky: No I didn’t, but patches are welcome.

  • quickredfos

    What about:

    ‘(function(json){ window.name = JSON.stringify( json ) })(INSERT_JSON_HERE)’

    Would that not work?

  • @quickredfos: yes, that looks fine.

  • gladenko

    The browser always write this in my console

    Unsafe JavaScript attempt to access frame with URL http://147.162.56.3:3000/ws/aa.wn?windowname=true from frame with URL http://localhost:3000/base/eracle. Domains, protocols and ports must match.

    my variable have data but this error/warning is correct?

  • Pingback: iframe height auto-resize « Sharovatov’s Weblog()

  • Vannak

    Has anyone gotten this to work correctly in IE10? It looks like the AJAX call is going through and coming back successfully but the callback is never firing.

  • Pingback: Cross domain iframe content load detection - Javascript Solution - Developers Q & A()

  • Pingback: QNimate – Same-origin policy in nutshell()

  • Pingback: SAU, Window.Name, JSON-RPC | Blog · Bitovi.com()