torsdag den 6. marts 2008

cross site javascript

This is an ajax widget I wrote, while learning about cross site scripting (xss). Read more about the Webspace wormhole here.

The idea is that on any page on any browser I should be able to embed this script and it will share content. Much like Google maps and a ton of other useful stuff from Yahoo and Google.

On the page itself the script only needs a small amount of information, like the id of the div it will use for the graphics and what 'tag' it will subscribe to.

The transport it uses is not the typical Ajax.Request from the prototype lbirary, because this uses solely XMLHttpRequest, which for security reasons default in browsers is not cross site.

Instead I had to write a transport of my own. The basic work-around is to embed a script element in the dom created by a dynamic page. This way, when the script is loaded it can inject data into the javascript execution, just like a plain script file. I implemented a reusable class for it, thusly:

var Transport = Class.create({
initialize: function(url, jsonCallback) {
this.url = url;
this.jsonCallback = jsonCallback;
},
activate: function() {
this._cleanUpScript(this.url);
var script_object = new Element('script', {src: this.url, type: 'text/javascript'});
var head=document.getElementsByTagName('head')[0] ;
head.appendChild(script_object);
this._xssScriptLoad();
},
_xssScriptLoad: function() {
var _this = this;
if(typeof(wh_xss_result) != 'undefined') {
this.jsonCallback(wh_xss_result);
void(wh_xss_result);
} else {
setTimeout(function(){_this._xssScriptLoad();}, 100);
}
},
_cleanUpScript: function(url) {
$A(document.getElementsByTagName('script')).each(function(el){
if(el.src == url){
el.remove();
};
});
}
});

The only 'gotcha' here is that I have to know the name of the variable that the result is stored in. This could be set on the serverside if I pass it as a parmater if I want the serverside to be more reusable, but for the sake of my little wormhole, I hardcoded the variable on both sides.

Here is an example usage of the transport:

var url = 'http://www.kennethhn.dk/webhole/get.php?tag=science';
var t = Transport(url, function(json){alert("json object = " + json});
t.activate();

In this case, the url is a reference to a php script on my site that returns a url for content submitted for the tag.

The second argument is a callback function, that will be called with the resulting json object.

The result might look like this:

var wh_xss_result = {
message: 'fetched url for tag science',
result: 'http://tbn0.google.com/images?q=tbn:-U28WILXKSXv5M:http://www.familycourtchronicles.com/philosophy/wormhole/wormhole-diagram.jpg'};

The transport class will then embed the result as a script and set a timeout event to repeat until the browser has loaded the script. Loading of the script is determined by the variable wh_xss_result, which will be 'undefined' until executed.

Xss can be very useful, but also very dangerous, just be vary of what scripts you choose to embed.

Update 13/04/2009: removed the WebSpace wormhole from this page.