Recently I started looking at my AJAX call security and found some code that uses tokens, request and referer in an attempt to authenticate the call and stop XSS and CSRF.

The AJAX calls are for the article list / article table in the admin section.

Note: The PHP will not run unless you are logged in — it uses a cookie and sessions to authenticate user.

EDIT: Implemented schisms function name suggestion.

The following code works as it should but is it a good method?

Create our Token:

$token = md5(rand(1000,9999)); 
$_SESSION['token'] = $token; 

The button to deactivate / activate an article:

if($article_active === 1){ 
echo '<input type="button" class="active_button" title="Deactivate" value="YES" name="'.$article_id.'"/>'; 
else { 
echo '<input type="button" class="active_button" title="Activate" value="NO" name="'.$article_id.'" />'; 
echo '

The AJAX call:

$(document).on("click",".active_button",function() {

    var form_data = {
        articleID: $(this).attr("name"),
        active: $(this).val(),
        selector: $("#selector").attr("name"),
        data: $("#data").val(),
        token:'<?php echo $token; ?>', 
        is_ajax: 1

    type: "POST",
    url: "controllers/articlecontrol.php",
    data: form_data,
    success: function(data){

The PHP that validates the AJAX request and sends the data to a PHP function:

if(isset($_POST['active']) && $selector === 'article') {

    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && isset($_POST['token']) && $_POST['token'] === $_SESSION['token']){

                $articleid = $_POST['articleID'];
                $active = ($_POST['active'] === 'YES') ? 0 : 1;
                $backend->setArticleStatus($articleid, $active);
            else {
                $_SESSION['status'] = '<div class="error">There was a Problem Activating / Deactivating that Article</div>';

The PHP activate / deactivate function (part of a class):

 * Activate / Deactivate Article w/Button

 public function setArticleStatus($articleid, $active) {
    $query = 'UPDATE wcx_articles SET article_active = :active WHERE article_id = :articleid';
    $stmt = $this->queryIt($query);
    $stmt = $this->bind(':active', $active);
    $stmt = $this->bind(':articleid', $articleid);
    if($this->execute()) {
        if ($active === 0) {
            $_SESSION['status'] = '<div class="success">Article Deactivated Successfully</div>';
        else {
            $_SESSION['status'] = '<div class="success">Article Activated Successfully</div>';
    else {
        $_SESSION['status'] = '<div class="error">There was a Problem Activating / Deactivating that Article</div>';
  • \$\begingroup\$ @AlexL Any thoughts? \$\endgroup\$
    – CodeX
    Commented Aug 16, 2014 at 15:16
  • \$\begingroup\$ @AlexGarrett any ideas? \$\endgroup\$
    – CodeX
    Commented Aug 17, 2014 at 10:52
  • \$\begingroup\$ A new '$token' is generated every 'AJAX' call \$\endgroup\$
    – CodeX
    Commented Aug 17, 2014 at 11:04
  • \$\begingroup\$ After testing XSS attacks it seems that $token stops them just fine. I am using $bits = 32; $token = bin2hex(openssl_random_pseudo_bytes($bits)); for the token now, so its truly random. \$\endgroup\$
    – CodeX
    Commented Aug 18, 2014 at 12:50

1 Answer 1

  • Prefer mt_rand() to rand().

  • Just a comment: your usage of tokens is similar to using nonces. There are established nonce generation libraries for PHP, and I suggest you take a look into them.

  • HTTP_X_REQUESTED_WITH is in general not a 100% reliable way to detect AJAX-ness. However, jQuery sends this header with its AJAX calls, so you should be okay. I'd suggest getting rid of the is_ajax in your request data though.

  • Your input element is at best confusing, and at worst messy. Why is Deactivate paired with YES, and Activate with NO? I'd prefer just using deactivate and activate as the button values, and templating inline:

    <td><input type="button" class="active_button" name="<?= $article_id ?>" value="<?= $article_active ? "de" : "" ?>activate" /></td>
  • activateDeactivate isn't a very good name. Maybe setActiveStatus or something?

  • \$\begingroup\$ So, apart from the obvious crappy code you pointed out, the AJAX authentication should stop XSS and CSRF? I just need the code to know the call came from the same domain and a valid trusted user \$\endgroup\$
    – CodeX
    Commented Aug 17, 2014 at 19:27
  • \$\begingroup\$ Title is deactivate, so if active is YES then the title on hover would be deactivate. \$\endgroup\$
    – CodeX
    Commented Aug 17, 2014 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.