From 07ce32dde019368151a22a797a4131c21d6f0329 Mon Sep 17 00:00:00 2001 From: Emanuele Cipolla Date: Fri, 16 Sep 2016 23:40:59 +0200 Subject: [PATCH 1/3] Random string should be more truly random --- .gitignore | 3 +++ README.md | 6 ++--- composer.json | 11 ++++---- composer.lock | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ nocsrf.php | 22 +++------------- 5 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 .gitignore create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0efd100 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +composer.phar +/vendor/ + diff --git a/README.md b/README.md index 3460040..4c36321 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ #NoCSRF, a simple PHP5 token class to prevent CSRF attacks. -* [Website](http://bkcore.com/blog/code/nocsrf-php-class.html) -* Author: Thibaut Despoulain -* Version: 1.0 +* [Website](http://emanuelecipolla.net/) +* Author: Thibaut Despoulain (until version 1.0), Emanuele Cipolla +* Version: 1.0.1 * Licensed under the MIT license \ No newline at end of file diff --git a/composer.json b/composer.json index 7d72b3e..8afe54e 100644 --- a/composer.json +++ b/composer.json @@ -1,14 +1,15 @@ { - "name": "bkcore/nocsrf", + "name": "gsdefender/nocsrf", "description": "A simple anti-CSRF token generation/checking class written in PHP5.", - "homepage": "http://bkcore.com/blog/code/nocsrf-php-class.html", + "homepage": "http://emanuelecipolla.net/", "license": "MIT", - "version": "1.0.0", + "version": "1.0.1", "type": "library", "require": { - "php": ">=5.3.2" + "php": ">=5.3.2", + "paragonie/random_compat": "^2.0" }, "autoload": { "classmap": [""] } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..850aea8 --- /dev/null +++ b/composer.lock @@ -0,0 +1,69 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "9330b54ed0fbd77ae4673baf4f25cfd2", + "content-hash": "589f172b295cddd4185563db96978018", + "packages": [ + { + "name": "paragonie/random_compat", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", + "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2016-04-03 06:00:07" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.2" + }, + "platform-dev": [] +} diff --git a/nocsrf.php b/nocsrf.php index 5f23398..9bde90a 100644 --- a/nocsrf.php +++ b/nocsrf.php @@ -8,6 +8,8 @@ * @author Thibaut Despoulain * @version 1.0 */ +require __DIR__ . '/vendor/autoload.php'; + class NoCSRF { @@ -90,30 +92,12 @@ 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 ) ); + $token = base64_encode( time() . $extra . bin2hex(random_bytes( 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; - } - } ?> From 2e38169cdaf24c28b1cce87d4733b51018e878dc Mon Sep 17 00:00:00 2001 From: Emanuele Cipolla Date: Fri, 16 Sep 2016 23:43:52 +0200 Subject: [PATCH 2/3] Copyright update --- nocsrf.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nocsrf.php b/nocsrf.php index 9bde90a..fc400a6 100644 --- a/nocsrf.php +++ b/nocsrf.php @@ -3,10 +3,13 @@ * NoCSRF, an anti CSRF token generation/checking class. * * Copyright (c) 2011 Thibaut Despoulain + * Copyright (c) 2016 Emanuele Cipolla + * * Licensed under the MIT license * * @author Thibaut Despoulain - * @version 1.0 + * @author Emanuele Cipolla + * @version 1.0.1 */ require __DIR__ . '/vendor/autoload.php'; From f8c2ee3e4320a4cdcb3c0b89067f6a4c8781b70c Mon Sep 17 00:00:00 2001 From: Emanuele Cipolla Date: Fri, 16 Sep 2016 23:49:06 +0200 Subject: [PATCH 3/3] Removing duplicate library copy --- example/example.php | 2 +- example/nocsrf.php | 119 -------------------------------------------- 2 files changed, 1 insertion(+), 120 deletions(-) delete mode 100644 example/nocsrf.php diff --git a/example/example.php b/example/example.php index 5fc4f24..78f2fb8 100644 --- a/example/example.php +++ b/example/example.php @@ -1,7 +1,7 @@ - * Licensed under the MIT license - * - * @author Thibaut Despoulain - * @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; - } - -} -?>