Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: b48a6e9454
Thibaut Despoulain
file 119 lines (103 sloc) 4.33 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
<?php
/**
* NoCSRF, an anti CSRF token generation/checking class.
*
* Copyright (c) 2011 Thibaut Despoulain <http://bkcore.com/blog/code/nocsrf-php-class.html>
* Licensed under the MIT license <http://www.opensource.org/licenses/mit-license.php>
*
* @author Thibaut Despoulain <http://bkcore.com>
* @version 1.0
*/
class NoCSRF
{

    protected static $doOriginCheck = false;

    /**
* Check CSRF tokens match between session and $origin.
* Make sure you generated a token in the form before checking it.
*
* @param String $key The session and $origin key where to find the token.
* @param Mixed $origin The object/associative array to retreive the token data from (usually $_POST).
* @param Boolean $throwException (Facultative) TRUE to throw exception on check fail, FALSE or default to return false.
* @param Integer $timespan (Facultative) Makes the token expire after $timespan seconds. (null = never)
* @param Boolean $multiple (Facultative) Makes the token reusable and not one-time. (Useful for ajax-heavy requests).
*
* @return Boolean Returns FALSE if a CSRF attack is detected, TRUE otherwise.
*/
    public static function check( $key, $origin, $throwException=false, $timespan=null, $multiple=false )
    {
        if ( !isset( $_SESSION[ 'csrf_' . $key ] ) )
            if($throwException)
                throw new Exception( 'Missing CSRF session token.' );
            else
                return false;
            
        if ( !isset( $origin[ $key ] ) )
            if($throwException)
                throw new Exception( 'Missing CSRF form token.' );
            else
                return false;

        // Get valid token from session
        $hash = $_SESSION[ 'csrf_' . $key ];

        // Free up session token for one-time CSRF token usage.
if(!$multiple)
$_SESSION[ 'csrf_' . $key ] = null;

        // Origin checks
        if( self::$doOriginCheck && sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) != substr( base64_decode( $hash ), 10, 40 ) )
        {
            if($throwException)
                throw new Exception( 'Form origin does not match token origin.' );
            else
                return false;
        }
        
        // Check if session token matches form token
        if ( $origin[ $key ] != $hash )
            if($throwException)
                throw new Exception( 'Invalid CSRF token.' );
            else
                return false;

        // Check for token expiration
        if ( $timespan != null && is_int( $timespan ) && intval( substr( base64_decode( $hash ), 0, 10 ) ) + $timespan < time() )
            if($throwException)
                throw new Exception( 'CSRF token has expired.' );
            else
                return false;

        return true;
    }

    /**
* Adds extra useragent and remote_addr checks to CSRF protections.
*/
    public static function enableOriginCheck()
    {
        self::$doOriginCheck = true;
    }

    /**
* CSRF token generation method. After generating the token, put it inside a hidden form field named $key.
*
* @param String $key The session key where the token will be stored. (Will also be the name of the hidden field name)
* @return String The generated, base64 encoded token.
*/
    public static function generate( $key )
    {
        $extra = self::$doOriginCheck ? sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) : '';
        // token generation (basically base64_encode any random complex string, time() is used for token expiration)
        $token = base64_encode( time() . $extra . self::randomString( 32 ) );
        // store the one-time token in session
        $_SESSION[ 'csrf_' . $key ] = $token;

        return $token;
    }

    /**
* Generates a random string of given $length.
*
* @param Integer $length The string length.
* @return String The randomly generated string.
*/
    protected static function randomString( $length )
    {
        $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijqlmnopqrtsuvwxyz0123456789';
        $max = strlen( $seed ) - 1;

        $string = '';
        for ( $i = 0; $i < $length; ++$i )
            $string .= $seed{intval( mt_rand( 0.0, $max ) )};

        return $string;
    }

}
?>
Something went wrong with that request. Please try again.