Simple Secure Remote Scripting using AJAX
So you want to make your web applications a little more life like, a little less boring, producing responses that make your web software appear in real time. My favorite way to go about doing it though, is using http calls, commonly referred to as AJAX. And while this method will do you little good at cleaning floors, it’s actually quite useful at data rendering.
I like to package my js into functions. That way, you’re not rewriting your code over and over again for simple tasks.
For the purposes of this post, let’s assume that you’ve already decided to do things this way, and that you want to get js code back so that you can manipulate your pages. What we’re going to do here is create a re-usable http call function called url, and try to parse what we get back as javascript.
function callback(incomingData, serverStatus)
{
// Called automatically when we get data back from server
//alert(incomingData);
//runs incoming data as js code.
eval(incomingData);
}
function url(destination)
{
//alert(destination);
var remoteScriptObject = null;
if (window.XMLHttpRequest) {
remoteScriptObject = new XMLHttpRequest();
} else {
remoteScriptObject = new ActiveXObject(“Microsoft.XMLHTTP”);
}
remoteScriptObject.onreadystatechange = function()
{
if (remoteScriptObject.readyState == 4 || remoteScriptObject.readyState == “complete”) {
callback(remoteScriptObject.responseText, remoteScriptObject.status);
}
Pretty cool, no?
So now, in theory you can execute anything on your webspace that outputs js from this handy dandy little set of functions. So if you had a piece of php code that looked something like this:
<?php
//turn cache off for IE
header(“Cache-Control: no-cache, must-revalidate”);
echo(“alert(’hallow world.’);”);
?>
you would be all set, right?
Wrong!
While all of this is a lot of fun, and works really well, the big sites like Google and Myspace have all found that doing this can expose code, or worse yet authenticated interfaces if you’re not careful, and could potentially leave databases wide open if left unchecked. The incident at Google last year was classified as a security flaw with Gmail that left everyone’s address books wide open, for about 48 hours after the vulnerability was discovered. They were quick to point fingers at the maker of the AJAX framework they used, and the maker in return promised a point of origination fix, but noted that most other AJAX frameworks were subject to the same problem.
But in reality, the problem that Google had wasn’t with their client side scripting libraries at all. It was a problem with the server side code that they had supporting them.
You see, irregardless as to which AJAX framework you’re using, whether or not you write your own, or borrow someone else’s to do it, you’re going to have a problem called “Point of origination” if you like it or not. And all that means is that there is absolutely no way to reliably ensure that your client side code will always know or care where it’s being executed from.
Part of the problem with the whole AJAX thing is that client side code can be modified and run by anybody, anywhere. So, even if the maker of the AJAX framework you’re using has made a Point of Origination fix, who’s to say that a reasonably talented hacker couldn’t undo it or even completely remove it if they wanted to, and run a modified version of your own code to get to your data?
The weakest link in the chain is going to be anything you find on the client side. Databases and web servers, you’ll remember, authenticate for a reason. But when you do a lot of client side coding to work with databases, you’re essentially letting in what amounts to unauthenticated connections. Man, that’s a huge security problem if you’re not prepared for it. And the truth of matter is that nothing you do to your javascript or AJAX code is going to make much of a difference as far as security.
So, that leaves us with the server side code. And the fix is really simple.
And the thing that makes it so easy is that unlike other kinds of scripting, with AJAX code there ALWAYS a referrer. All you need to do is validate your referrer every time the script the runs.
So we go from this:
<?php
//turn cache off for IE
header(“Cache-Control: no-cache, must-revalidate”);
echo(“alert(’hallow world.’);”);
?>
To This: (Mind you, in a real world example, you would probably be distributing this code between files, depending on how you’re set up)
<?php
function validate()
{
//in this case, we’re checking to see if the referrer and the script are on the same server. You can specify if you like.
$host = $_SERVER[‘SERVER_NAME’];
$ref = explode(“/”, $_SERVER[‘HTTP_REFERER’]);
//so in theory, we know that a properly formatted request will alway put the domain name at the second position from zero.
//But just to be safe, we’re going to assume that only hackers use @ in web addresses when accessing http sites to get around things like this.
$check4hacker = strrpos($ref[2], ‘@’);
$check4hosts = strcmp($host, $ref[2]);
if ($check4hosts == -1 | $check4hacker != false | strlen($_SERVER[‘HTTP_REFERER’]) == 0)
{
//stops it cold. If you want to process the result, have the function return something here.
//maybe adding a call to a logging function wouldn’t hurt either.
echo(‘internal error’);
exit;
}
}
//always call this before doing anything:
validate();
//the original tidbit of code:
//turn cache off for IE
header(“Cache-Control: no-cache, must-revalidate”);
echo(“alert(’hallow world.’);”);
?>
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

