Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
NoCSRF
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 4
420
0.00% covered (danger)
0.00%
0 / 1
 check
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
240
 enableOriginCheck
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 generate
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 randomString
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * NoCSRF, an anti CSRF token generation/checking class.
4 *
5 * Copyright (c) 2011 Thibaut Despoulain <http://bkcore.com/blog/code/nocsrf-php-class.html>
6 * Licensed under the MIT license <http://www.opensource.org/licenses/mit-license.php>
7 *
8 * @author Thibaut Despoulain <http://bkcore.com>
9 * @version 1.0
10 */
11class NoCSRF
12{
13    protected static $doOriginCheck = false;
14    /**
15     * Check CSRF tokens match between session and $origin.
16     * Make sure you generated a token in the form before checking it.
17     *
18     * @param String $key The session and $origin key where to find the token.
19     * @param Mixed $origin The object/associative array to retreive the token data from (usually $_POST).
20     * @param Boolean $throwException (Facultative) TRUE to throw exception on check fail, FALSE or default to return false.
21     * @param Integer $timespan (Facultative) Makes the token expire after $timespan seconds. (null = never)
22     * @param Boolean $multiple (Facultative) Makes the token reusable and not one-time. (Useful for ajax-heavy requests).
23     *
24     * @return Boolean Returns FALSE if a CSRF attack is detected, TRUE otherwise.
25     */
26    public static function check( $key, $origin, $throwException=false, $timespan=null, $multiple=false )
27    {
28        if ( !isset( $_SESSION[ 'csrf_' . $key ] ) )
29            if($throwException)
30                throw new Exception( 'Missing CSRF session token.' );
31            else
32                return false;
33
34        if ( !isset( $origin[ $key ] ) )
35            if($throwException)
36                throw new Exception( 'Missing CSRF form token.' );
37            else
38                return false;
39        // Get valid token from session
40        $hash = $_SESSION[ 'csrf_' . $key ];
41
42        // Free up session token for one-time CSRF token usage.
43        if(!$multiple)
44            $_SESSION[ 'csrf_' . $key ] = null;
45        // Origin checks
46        if( self::$doOriginCheck && sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) != substr( base64_decode( $hash ), 10, 40 ) )
47        {
48            if($throwException)
49                throw new Exception( 'Form origin does not match token origin.' );
50            else
51                return false;
52        }
53
54        // Check if session token matches form token
55        if ( $origin[ $key ] != $hash )
56            if($throwException)
57                throw new Exception( 'Invalid CSRF token.' );
58            else
59                return false;
60        // Check for token expiration
61        if ( $timespan != null && is_int( $timespan ) && intval( substr( base64_decode( $hash ), 0, 10 ) ) + $timespan < time() )
62            if($throwException)
63                throw new Exception( 'CSRF token has expired.' );
64            else
65                return false;
66        return true;
67    }
68    /**
69     * Adds extra useragent and remote_addr checks to CSRF protections.
70     */
71    public static function enableOriginCheck()
72    {
73        self::$doOriginCheck = true;
74    }
75    /**
76     * CSRF token generation method. After generating the token, put it inside a hidden form field named $key.
77     *
78     * @param String $key The session key where the token will be stored. (Will also be the name of the hidden field name)
79     * @return String The generated, base64 encoded token.
80     */
81    public static function generate( $key )
82    {
83        $extra = self::$doOriginCheck ? sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) : '';
84        // token generation (basically base64_encode any random complex string, time() is used for token expiration) 
85        $token = base64_encode( time() . $extra . self::randomString( 32 ) );
86        // store the one-time token in session
87        $_SESSION[ 'csrf_' . $key ] = $token;
88        return $token;
89    }
90    /**
91     * Generates a random string of given $length.
92     *
93     * @param Integer $length The string length.
94     * @return String The randomly generated string.
95     */
96    protected static function randomString( $length )
97    {
98        $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijqlmnopqrtsuvwxyz0123456789';
99        $max = strlen( $seed ) - 1;
100        $string = '';
101        for ( $i = 0; $i < $length; ++$i )
102            $string .= $seed[intval( mt_rand( 0.0, $max ) )];
103        return $string;
104    }
105}
106?>