InformIT

How to Secure AJAX Requests

Date: Sep 1, 2006

Article is provided courtesy of Sams.

Return to the article

It's always important to implement some sort of security model in your database-enabled AJAX applications, says Kris Hadlock. Otherwise, you leave your database completely exposed. In this article, he shows a relatively simple procedure for including password verification in an AJAX/database interaction.

Introduction

When integrated with a database, AJAX can accomplish some extremely powerful interactions that are unique to the set of languages it encompasses. "With great power comes great responsibility," however, and database-integrated AJAX is no exception to this rule. To protect our database from unwanted requests, we need to have an interaction model that verifies the source of the request based on a password. In this article, we’ll cover how to create a password-protected AJAX request from the client side that’s verified on the server side before any database interactions occur. We’ll use PHP to create our unique passwords on the client side and also to verify them on the server when the AJAX requests are made.

Getting Started

To follow along with the examples, you’ll need to download the source files. (You can also view a live sample.) This article uses an AJAX engine that I created in order to abstract our AJAX requests and help us to share AJAX engine code between different applications. In order to use this engine, we simply import three JavaScript files and make requests to an object named AjaxUpdater. The engine will handle the rest, including delegating the response to the callback method specified in the request. Here’s an example of how we’ll make requests with this engine as well as import the associated files:

<script type="text/javascript" src="javascript/model/Ajax.js"></script>
<script type="text/javascript" src="javascript/model/HTTP.js"></script>
<script type="text/javascript" src="javascript/model/AjaxUpdater.js"></script>
<script type="text/javascript">
    document.load = AjaxUpdater.Update(’GET’, URL, callback);
</script>

Clearly, it’s fairly simple to import the JavaScript objects and make a request using this engine. Let’s get started by creating the passwords for our requests.

Creating a Password for Our AJAX Requests

In order to make a password-protected AJAX request, we’ll need to create a method that produces the password. Since this is a password that we’re creating for security reasons, we should use a server-side language to produce the password, so that the code is hidden from the client. This wouldn’t be the case if we used JavaScript to produce the password, because the code would be accessible to any savvy web user. For these reasons, we’ll use PHP to produce the password that we’ll send along with our AJAX request.

First, we need to create a PHP class that will contain all of the code that we write for password management. Let’s name this class PasswordManager. We’ll make this class a Singleton, meaning that it can be instantiated only once. The idea is that we can access it from anywhere in our application without having multiple instances of the object. Here’s the code to create the class and make it a Singleton:

<?
class PasswordManager
{

    private function PasswordManager(){}

    public static function getInstance()
    {
       static $instance;
       if (!is_object($instance))
       {
           $instance = new PasswordManager();
       }
       return $instance;
    }
}
?>

Now that we have our Singleton object created, we’ll add a string named $pass, which will be equal to any custom string that we choose. This property should be changed to something unique; I simply used the value mypassword as a default. (If you’re planning to use this object in your AJAX applications, it’s very important to change the password to your own string—and possibly change it frequently.) Here’s the code to add the $pass array to our PasswordManager object:

private $pass;

private function PasswordManager()
{
    $this->pass = "mypassword";
}

We have made the $pass property private so that the password cannot be retrieved from outside of the class. When we have our password ready, we can add a method to be used to create a cookie version of our password on the server side and use it to protect our requests. We’ll create a method named createPassword to handle this functionality:

public function createPassword()
{
    // Set a cookie with an encrypted version of the password for one day
    setcookie("uid", md5($this->pass), time() + 86400, "/", ".krishadlock.com", false);
}

The createPassword method is fairly simple, as it doesn’t take any parameters and returns a unique password with little effort. The code in this method sets a cookie named uid on the server with a value that’s an MD5-encrypted version of our $pass property. The cookie is set to expire in a day in case the user is on a shared computer and other users have access to the application that we’re creating. The next parameter is the domain in which the cookie is saved, which makes it harder for a hacker to fabricate a cookie. The last parameter is a Boolean value that indicates whether the server is secure or HTTPS, which in this case is equal to false.

Making a Password-Protected AJAX Request

With this new PasswordManager and its associated methods, we can easily add a unique password to our AJAX requests. In order to do this, we’ll create a PHP file that will be used to display on the client side. The first thing that we’ll do in this new PHP file is import the PasswordManager, get its instance, and create a unique password:

<?
    require_once("classes/PasswordManager.class.php");
    $pwManager = PasswordManager::getInstance();
    $pwManager->createPassword();
?>

Now that we have the password, let’s import the JavaScript objects that make up our AJAX engine:

<script type="text/javascript" src="javascript/model/Ajax.js"></script>
<script type="text/javascript" src="javascript/model/HTTP.js"></script>
<script type="text/javascript" src="javascript/model/AjaxUpdater.js"></script>
<script type="text/javascript">
    function sendProtectedRequest()
    {
       AjaxUpdater.Update(’GET’, ’xmlServiceConnector.php’, displayResponse);
    }

    function displayResponse()
    {
       if(Ajax.checkReadyState(’loading’) == "OK")
       {
           alert(Ajax.request.responseText);
       }
    }
</script>

With this code in place, we have all of the objects that we need in order to make the request, and two methods to send and receive data on the server side. The sendProtectedRequest method is using the AjaxUpdater object to make a request on a file called xmlServiceConnector, which we’ll use to verify the request by checking to see whether the cookie exists; then it passes the displayResponse method as a callback. The xmlServiceConnector file is an intermediate file that verifies the password before delegating the request to the appropriate PHP class, which then could make a database connection. We won’t focus on the database connection part in this article, but we’ll create the intermediate file to understand how the password is verified on the server side.

Verifying the AJAX Request

Now that we’re saving the password as a cookie from our index page, we’ll need to verify it on the server side when the AJAX requests are made. To do this, we’ll create a file called xmlServiceConnector.php, which we’re already requesting in our client-side PHP file. This file will contain the following code:

<?php

require_once("classes/PasswordManager.class.php");
$pwManager = PasswordManager::getInstance();

header("Content-Type: application/xml; charset=UTF-8");
echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n";

if( $pwManager->verifyPassword() )
{
    echo "<response>The request was successful!</response>";
}
else
{
    echo "<response>The request was not successful.</response>";
}

?>

This file first imports and gets an instance of the PasswordManager. It then includes a header that specifies the Content-Type of the file as XML, so that the response on the client side is valid XML. An XML declaration is also added to the page because it’s necessary to create a valid XML structure.

With this code in place, we can verify the password that was set in the page that should now be making the AJAX request. If the cookie password doesn’t exist, we know that the request is coming from an invalid location, and we don’t return any useful data. By calling the verifyPassword method in the PasswordManager, we can determine whether the password was previously set. Based on the Boolean, we’ll return the appropriate response to the requesting object. The verifyPassword method should be added to the PasswordManager, and should contain the following code:

public function verifyPassword()
{
    if($_COOKIE["uid"] == md5($this->pass))
    {
       return true;
    }
    else
    {
       return false;
    }
}

This method simply looks for the cookie named uid and checks whether it’s equal to an MD5-encrypted version of the $pass property. This step ensures that the cookie exists and that the cookie was created by using our unique password. In this example, we’re simply returning an XML node as a response, but this is the location where we would connect to other PHP files that would in turn connect to the database.

To test the reliability of this security model, try to make a request directly into a browser that doesn’t already have the cookie set:

http://www.krishadlock.com/clients/informit/secureajax/xmlServiceConnector.php

Without your first accessing the application that’s setting the unique cookie, all requests will be rejected.

Conclusion

This is just one of many ways to secure your AJAX requests and ensure the integrity of the data that’s being sent to your database. It’s always important to implement some sort of security model in your database-enabled AJAX applications; otherwise, you leave your database completely exposed. As you’ve seen in this article, it’s not very difficult to implement a solution that protects your data, and variations of this example can easily be achieved.

800 East 96th Street, Indianapolis, Indiana 46240