John Squibb

Using Tokens to Thwart Cross-Site Request Forgeries

A Cross-Site Request Forgery (CSRF) occurs when an attacker supplies a link or script that causes a user to access a page on another site where that user is presumed to have been logged in. For example, an attacker could provide a link for a social network site to an unsuspecting user logged-in at that site, causing that user to add the attacker to their friends list. Another scenario could cause the user to transfer funds from their bank account to the account of the attacker.

CSRF issues surface when the destination website blindly trusts that the authenticated user intends to perform the action the attacker commands. There are several methods for thwarting such exploits. Today, we'll cover the use of tokens to safeguard against CSRF.

Implementing Single-use Tokens

When generating links that require a user action, we can attach a token in the following manner:

http://example.com/action?token=abcdefg

The format of the token isn't important, so long as it is random, hard to guess, and temporary. The following code demonstrates how to generate a randomized token:

<?php
// Generate a randomized token
$token md5(microtime(TRUE) . rand(0100000));

// Save the token to session
session_start();
$_SESSION['token'] = $token;

// Add an expiration date to prevent fixation.
$_SESSION['token-expires'] = time() + 1800;

Toggle plain-text

In this example, we generate the randomized token, store it in the session for comparison later, and for extra security, set an expiration time for the token of 30 minutes. After that amount of time, we won't honor the token any longer. This can help prevent token fixation in the event that an attacker somehow acquires access to a tokenized link intended for the user.

When processing the action for the supplied link, we can check for the required token as follows:

<?php
// Get the form token.
$supplied_token $_GET['token'];

// Ensure that a token has been previously set.
session_start();
if (!isset(
$_SESSION['token'], $_SESSION['token-expires']))
{
    die (
'token is required!');
}

$token $_SESSION['token'];
$expires $_SESSION['token-expires'];

// Clear the tokens, they are single use.
$_SESSION['token'] = NULL;
$_SESSION['token-expires'] = 0;

if (
$expires time() || $token != $supplied_token)
{
    die (
'Invalid or expired token!');
}
else
{
    print 
'Token good!';
}

Toggle plain-text

This snippet examines the visited page for the required token, checks the session, and ensures that the token matches, and that it has not expired. Also, we immediately wipe the token, as it is single-use only.

Using POST instead of GET or REQUEST

Another angle for CSRF exploitation can involve form data. If a particular form accepts GET or REQUEST data on the server side, then a malicious attacker could provide such data in the form of a link, image tag, etc. This could potentially emulate a user filling out and submitting the form on-site. There are two ways to thwart this behavior:

Including a token with a form is easy. Simply generate the token in the same fashion as previously explained, and supply it as a hidden input field in the form. On submit, check that the token matches the stored token, erase it, and redirect/error as appropriate.

Checking Referrers

Another way to thwart CSRF is to ensure that the page from which the user arrived is the expected origination for an action. For example, if we know that a user must always come from the http://example.com/profile page to affect the http://example.com/profile/edit page, then we can reasonably detect this from within our code by checking the HTTP referer. The downfalls to this are as follows:

Use your best judgment when deciding which mechanisms to employ, and don't be afraid to use a combination of checks where appropriate.

Read More

This article is one in a several-part series on PHP security. View all the articles

Suggested Reading

PHP Objects, Patterns, and Practice

by Matt Zandstra

Apress' PHP Objects, Patterns, and Practice is great for beginners and veterans alike. The first several chapters focus entirely on the foundations of Object-Oriented PHP (OOPhp), while later chapters teach various patterns such as the Factory, Singleton, Observer, and more. The author, Matt Zandstra, places major emphasis on good programming habits and strives to teach as many enterprise level practices as space allows. The last chapters introduce the reader to a series of productivity tools which cover version control, documentation, automated builds, and unit testing. This text will complement any OOPhp application developer, and I recommend it to anyone looking to dive in, or a seasoned OOPhp developer looking to pick up some new tricks and tools.

Suggested Reading

Mastering Regular Expressions

by Jeffrey E.F. Friedl

This is a must-read for anyone interested in learning the complexities of regular expressions usage. Make no mistake, this book is not a quick reference, but rather an all-in tome of regular expression goodness. Even if you only use the occasional regex to validate emails, phone numbers, credit cards, or other, this book will give you an excellent understanding of how regular expressions perform such tasks.

Tags: Security, Tokens, CSRF, Cross-Site Request Forgery
Short URL: http://sqb.in/z2tQ