2
\$\begingroup\$

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:

<td>
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 '
</td>

The AJAX call:

// ACTIVATE / DEACTIVATE WITH LINK
$(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
    };

    $.ajax({
    type: "POST",
    url: "controllers/articlecontrol.php",
    data: form_data,
    success: function(data){
        document.location.reload(true);
    }
    });
});

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

// ACTIVATE / DEACTIVATE w/BUTTON
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>';
    }
 }
\$\endgroup\$
  • \$\begingroup\$ @AlexL Any thoughts? \$\endgroup\$ – CodeX Aug 16 '14 at 15:16
  • \$\begingroup\$ @AlexGarrett any ideas? \$\endgroup\$ – CodeX Aug 17 '14 at 10:52
  • \$\begingroup\$ A new '$token' is generated every 'AJAX' call \$\endgroup\$ – CodeX Aug 17 '14 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 Aug 18 '14 at 12:50
2
\$\begingroup\$
  • 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?

\$\endgroup\$
  • \$\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 Aug 17 '14 at 19:27
  • \$\begingroup\$ Title is deactivate, so if active is YES then the title on hover would be deactivate. \$\endgroup\$ – CodeX Aug 17 '14 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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