Monday 26 August 2013

Advanced CSRF Token PHP Generation Class

Today, I am going to share the CSRF (Cross Site Request Forgery ) PHP Generation Class, Which is used to prevent the invalid access to the web application using $_GET and $_POST Requests. Here is the PHP Code

// This class requires Session, start it, if not already exist

if (!isset($_SESSION)) {
    session_start();
}

class CSRFToken {

    private static $csrf_tokenObj = NULL;
    private $csrf_token;
    private $csrfTokenKey = 'sureshdotariya';
    private $csrf_token_last_cleaned = NULL;
    private $csrf_token_validity = 600; // 10 minutes in seconds

    private  function __construct() {}

    /**
     * @desc Get our singleton reference
     */

    public static  function getInstance() {

        if (self::$csrf_tokenObj == NULL) {
            self::$csrf_tokenObj = new CSRFToken();
        }
        return self::$csrf_tokenObj;
    }

    /**
     * Generate CSRF Token using sha256 algorithm and store in User Session
     */

    private   function _generate() {

        if (!isset($_SESSION['csrf_tokens'])) {
            $_SESSION['csrf_tokens'] = array();
        }

        //generate the hash token

        $this - > csrf_token = hash_hmac('sha256', openssl_random_pseudo_bytes(32), $this - > csrfTokenKey);

        $_SESSION['csrf_tokens'][$this - > csrf_token] = time();

    }

    /**
     * Validate Token against the token from form
     * @param String $formToken
     * @return boolean
     */

    public   function validate($formToken) {

        /*
         * Just do array lookup on the token, don't need to loop through the array.
         */

        if (!is_array($_SESSION['csrf_tokens']) || !isset($_SESSION['csrf_tokens'][$formToken])) {

            return false;
        }

        $tokenValid = false;

        //token is valid if it generated time is less than 10 minutes.

        if ((time() - $_SESSION['csrf_tokens'][$formToken]) <= $this - > csrf_token_validity) {

            $tokenValid = true;
        }

        /*
         * only destroy the current one that we're validating,
         * user might have several forms open that is using this obj
         */

        $this - > _destroy($formToken);
        return $tokenValid;

    }

    /**
     * generate the CSRF token value and store in session
     * (This method is used to display token in form hidden field)
     * @return string
     */

    public   function getToken() {

        $this - > _generate();
        return $this - > csrf_token;
    }

    /**
     * Destory CSRF Token
     */

    private    function _destroy($formToken) {

        //destroys the token

        unset($_SESSION['csrf_tokens'][$formToken]);

        if (!isset($this - > csrf_token_last_cleaned)) {
            $this - > csrf_token_last_cleaned = time();
        } else {
            $curTime = time();

            //if the last time we've cleaned the expired tokens was greater than the token validity time

            if (($curTime - $this - > csrf_token_last_cleaned) > $this - > csrf_token_validity) {

                //then loop through and clean out all the expired tokens
                $this - > _destroyExpiredTokens();
                //reset the last cleaned time
                $this - > csrf_token_last_cleaned = $curTime;

            }

        }

    }

    /**
     * Destory expired tokens
     *
     * Loops through the token storage and destroys expired tokens.
     * This is to prevent the token storage from growing too big.
     *
     * @return void
     */

    private   function _destroyExpiredTokens() {

        if (!empty($_SESSION['csrf_tokens'])) {
            $curTime = time();
            foreach($_SESSION['csrf_tokens'] as $tokenKey = > $timeStamp) {

                //if the timestamp doesn't exist or is greater than the allowed validity time

                if (!is_numeric($timeStamp) || ($curTime - $timeStamp) > $this - > csrf_token_validity) {

                    //unset the expired token
                    unset($_SESSION['csrf_tokens'][$tokenKey]);
                }
            }
        }
    }
}

How to generate CSRF Token:

In order to generate CSRF Token, you need to use the following PHP Code

$csrf_tokenObj = CSRFToken::getInstance();
$token = $csrf_tokenObj->getToken();

How to validate CSRF Token:

In order to validate CSRF Token with the Stored Token in the Session, here is the php code

$originalToken = "8cf2179dea80ddf3a5c5d67757ca9d0c9d274e2f3b";
$csrfTokenObj = CSRFToken::getInstance();

if($csrfTokenObj->validate($originalToken)){
          echo "your request is valid";
}else{
         echo "your request is invalid";
}

Hope, you enjoyed this Post.

No comments:

Post a Comment