Zend PHP 5 – Security – Cross Site Request Forgery

Cross Site Request Forgery (CSRF) is a type of attack that occurs when a malicious Web site, email, blog, instant message, or program causes a user’s Web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.

URLs on websites can sometimes reflect the actions that they perform. Take an example of a user that’s registered on a website that has an active subscription to an certain section of interest. A way of deactivating the subscription could be as simple as navigating to the URL http://www.somesite.com/membership/deactivate

The problem with this is that attackers could put a link on some page or email and try to dupe the user into clicking on it. Even easier, they could get the user to go to some page of the attacker’s website which does nothing more than redirect to the deactivation URL. In addition, the attacker could get the user to go to a page containing a broken image link to that URL.

When retrieving the URL the user’s browser will automatically send the attacker’s session cookie to the www.somesite.com domain which would detect the user is still logged in, and the user’s subscription would be deactivated.

Luckily, there are ways of preventing CSRF attacks.

We can add a unique key or token to each form through a hidden input field.

<form ...>
    <input type="hidden" name="form_key" value="<?php echo getFormKey(); ?>" />
    <!-- Some other fields below -->
</form>

The key would come from a function that randomly generates a string, like the below for example:

function getFormkey() {
    if (!isset($_SESSION['form_key'])) {
        $formKey = bin2hex(openssl_random_pseudo_bytes(32));
        $_SESSION['form_key'] = $formKey;
    } else {
        $formKey = $_SESSION['form_key'];
    }
    return $formKey;
}

When the form is submitted, compare the form key submitted in the form field with the form key stored in the session.

$formKey = $_REQUEST['form_key'];

if ($formKey == $_SESSION['form_key']) {
    // Okay to proceed
} else {
    // Potential CSRF attack
}

We can also use measures such as requiring the user to re-login for sensitive operations.

Note: This article is based on PHP version 5.5.