Monday, September 13, 2010

How To: Getting Around the AJAX Same-Origin Policy

If you've ever done any kind of AJAX development, you're probably aware of the same-origin policy that most web browsers enforce. This policy dictates that any AJAX request made by a web page may only request data from the domain from which it was served. In other words, http://www.example.com/index.html can only make AJAX requests to any page or script on example.com or any of its subdomains. The reason for this policy is that if any external data is malicious, it would open up your web page to a host of cross-site scripting vulnerabilities.



Just recently, I decided to write a simple weather update page, using AJAX and XML data from a weather website. The problem is, I can't request my weather XML data from "www.weatherexample.com" because I'm either viewing my weather web page on my own web server, or locally on my PC.

The key to solving this problem is server-side scripting. If you have the ability to run any kind of server-side programming language where you are hosting your AJAX web page, you can get around the same-origin policy. It is possible to set up a server-side script that acts as a relay for the XML data you're trying to reach. A server-side script can go and get HTTP data from anywhere on the open web, with no restrictions. The script could then relay that data back down to your AJAX web page, provided it was the same server that served your AJAX web page in the first place. The following diagram should illustrate the concept more clearly:


So how do you get your server-side script to grab XML data for you, and pass it along back to you? The steps are as simple as obtaining the data and storing it into a variable, then printing that data with the appropriate headers. I've included two examples, one in PHP, and one in Perl.

Perl:

#!c:\perl\bin\perl.exe
use strict;
use LWP::Simple;
use CGI;
my $cgi = new CGI;
print $cgi->header("text/xml");
my $qs = $ENV{'QUERY_STRING'};
$qs =~ /url=(.*)/;
my $url = $1;
getprint($url) || die $!;

PHP:

<?php
$url = $_GET["url"];
$content = file_get_contents($url);
header('Content-type: text/xml');
echo $content;
?>


Save either of these very simple scripts on your web server (depending on what language the server is set up for), then make all your AJAX requests to

http://yourserver.com/ajax.pl?url=http://examplexml.com/data.xml

or

http://yourserver.com/ajax.php?url=http://examplexml.com/data.xml

This how-to comes with a warning: only bypass the same-origin policy if you control or completely trust the external XML data. Otherwise, the vulnerabilities mentioned above can become a possibility.

3 comments:

gglggl said...

you forgot <? at start of PHP example

gglggl said...

you forgot the <? at the start of the PHP example

Mikazo said...

Thank you, it's fixed now.