Cross Site Request Forgery Prevention in PHP

Preventing Cross Site Request Forgery With PHP Applications

Cross Site Request Forgery, aka CSRF and XSRF can be performed by targeting an authenticated web page when a user is logged in to a site, or, the user session(s) are still valid.

A popular method to perform this kind of attack is to draw a user to a webpage, like a forum or blog comment with a link that goes to a post page; such as one that could perform a delete request. Meanwhile, since the user is authenticated via valid sessions, it will perform the task at hand.

If the post page does an automatic update or deletion, or grabs information via the url using $_GET, that makes it even worse; since filtering and other such methods are not implemented.

Now, that you see that the post request is instigated from a foreign url, there are procedures that can stop this behavior in its tracks. The method being shown below uses a class and sessions that can ensure the post from the link will not do damage. This example can be used on pages that are submitted to itself, or, those that are submitted to another page.

Here is how it works.

1. Create a class called csrf and include it on the top of the file.

include("Classes/csrf.php");

2. Add the class code into the file csrf.php.The code below will do the work.

<?php

class csrf
{
    public $csrf;
    public $session;
    public $csrf_array = array();

    public function __construct()
    {
        $csrf = hash("sha1", rand() . time() . rand());
        $_SESSION['csrf'] = $csrf;
        $session = $_SESSION['csrf'];
        $this->MakeToken($csrf, $session);
    }

    public function MakeToken($csrf, $session)
    {
        $this->csrf = $csrf;
        $this->session = $session;

        array_push($this->csrf_array, $this->csrf, $this->session);
        return $this->csrf_array;
    }

}

3. Add the code below into the form file. This code only occurs when you land on a page that is not posted, or if the $_SESSION['csrf'] does not exist. If the page was posted from elsewhere, it would not exist, thus, it is created.

For example, if you had a page to delete members and came there securely, it would not have any post variables. Thus, the code below runs and calls the csrf class. In the example below, the class returns the property $csrf->session and uses it to make the $_SESSION['csrf'] variable. 

That variable was created using functions in the class.

if (count($_POST) < 1 || !isset($_SESSION['csrf'])) {
    $csrf = new csrf();
    $_SESSION['csrf'] = $csrf->session;
}

4. Wrap the database code into the check. If you are tricked into clicking this link, your page will have the code below to ensure it is not from another site.

Since the code from the previous example will create the session for validation purposes only when the page has no post variables, or it has no $_SESSION['csrf'] variable, it will mismatch with the form submitted elesewhere.

Therefore, if it came posted from a form that was submitted from somewhere else(Cross Site) via a form submission or Javascript automatically submitting the form when you click a link, it will arrive at your page and the session variable from your site would invalidate the form because it needs to have the same token from a hidden input field as the one you created from the csrf class.

The code below clearly shows that if there is a match, do the database stuff, and, if not, it prints that there is a token mismatch.     

if (htmlspecialchars($_POST['csrf'], ENT_QUOTES, 'UTF-8') == $_SESSION['csrf']) {
///do database work
 echo "Token matched! This was not cross site!";
} else {
            echo "Token Mismatch! Reload page and start over!";
        }        
            $csrf = new csrf();
            $_SESSION['csrf'] = $csrf->session;

5. Add a hidden field into the form. This line below places a value from the token that was created in the csrf class. It is a number that a fake form would not have in order to match your value from the csrf class.

<input type="hidden" name="csrf" value="<?php echo $csrf->session; ?>"/>

Extras
Now the next question you may have is, "How the heck could someone time my opened session with the link and auto form submission?"

Although this may seem like a very unlikely condition, there are many methods for which this could take place. Clever hackers can figure out what pages are visited on a network, such as wifi cafes. This can provide details about a page or script; especially if it is something common like WordPress.

It could also show details about your email address. Thus, you could be lead from a mysterious email sending you to a page that performs this operation because you feel the need to click the link.

Protect Yourself
Although web applications can be secured from the coding, you can always keep problems minimized by not trusting strange emails, logging out after using an application, and not allowing sessions to stay alive for extended periods of time. If you are logged out, the CSRF attack would have not had even had gone to the checking stage.