When you integrate AJAX technology in your Web application, you are exposed to security problems on call requests. Here is a simple solution to secure your calls...

Context:

To build your AJAX request, you must create a Javascript function which call a HTTP ressource in your web application.

For instance, a request that modify a plugin activation through the url http://www.myapp.ext/ajax/myplugin.

The main security problem is when anyone knows the url endpoint: this person can modify the plugin activation state, and then causing a security breach in your Web application.

The idea is to implement a functionality which identify only the person, connected to your Web application, who request the state modification.

Analysis

There are some methods to secure AJAX calls.

I give you a simple solution, that use php session, in which a random key is generated and saved in session, then used in AJAX request to validate the call request.

The new url endpoint is http://www.myapp.ext/ajax/myplugin?skey=<Random key>.

Implementation

1. Server side: Generate random key

The aim is to generate a random key and save it in the session, then use it during building of the javascript function.

Using Symfony implementation

// AcmeBundle/Controller/PluginController.php

// Controller Action
public function indexAction(Request $request)
{
  $session = $request->getSession();
  if (!($session->isStarted())) {
    $session->start();
  }
  $server_key = $session->get('skey');
  if(empty($server_key)){
    $server_key = $this->randomString();
    $session->set('skey', $server_key);
  }

  return $this->render('AcmeBundle:Plugin:index.html.twig', array(
    'server_key'  => $server_key  // Pass random key to twig template
  ));
}

// Random string generator
private function randomString($length = 10){
  $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  $charactersLength = strlen($characters);
  $randomString = "";
  for ($i = 0; $i < $length; $i++) {
    $randomString .= $characters[rand(0, $charactersLength - 1)];
  }
  return $randomString;
}

Using PHP implementation


session_start();

// Random string generator
function randomString($length = 10){
  $characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  $charactersLength = strlen($characters);
  $randomString = "";
  for ($i = 0; $i < $length; $i++) {
    $randomString .= $characters[rand(0, $charactersLength - 1)];
  }
  return $randomString;
}

if(!isset($_SESSION['skey'])){
  $_SESSION['skey'] = randomString();
}

2. Client side: Build javascript function

A POST request is created with parameters active which enable the plugin.


$.ajax({
  url: "http://www.myapp.ext/ajax/myplugin?skey=<Server key>",
  method: 'POST',
  data: {active: <Activation state> }
}).done(function () {
  //<Action when the request successes>
});

with:

  • <Server key>: The server key => Use {{ server_key }} using symfony implementation in Twig template or <?php echo $_SESSION['skey']; ?> using PHP implementation.
  • <Activation state>: The activation state (0 or 1).
  • <Action when the request successes>: What you have to do when the request successes.

3. Server side: Treatment of request

When the HTTP resource is called, a check with the server key is done.

Using Symfony implementation


// AcmeBundle/Controller/PluginController.php

// Controller Action
public function activationAction(Request $request)
{
  if($request->isMethod('POST')) {
    $session = $request->getSession();

    if (!($session->isStarted())) {
      $session->start();
    }

    $server_key = $session->get('skey');
    $client_key = $request->query->get('skey');

    // >>>> Security check
    if(empty($server_key) || empty($client_key) || ($server_key != $client_key)) {
      return new Response("Unauthorized", Response::HTTP_UNAUTHORIZED);
    }

    //Treatment to do to (de)activate plugin

    return new Response("Accepted", Response::HTTP_ACCEPTED);
  }

  return new Response("Bad Request", Response::HTTP_BAD_REQUEST);
}

Using PHP implementation


session_start();

// >>>> Security check
if(empty($_SESSION['skey']) || empty($_POST['skey']) || ($_SESSION['skey'] != $_POST['skey'])) {

  //Treatment when a bad user do the request

} else {

  //Treatment to do to (de)activate plugin

}

Conclusion

Here is a simple solution to secure your AJAX calls against unexpected requests.

You can also adapt this strategy to other technologies.

Other solutions do exist (more complex and more safier) but this one is enough to figh against the main attacks.

See you on the next article... xD

Previous Post Next Post


Add a comment