├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── phpunit.php ├── phpunit.xml ├── src └── CSRF.php └── tests └── CSRF.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_* 2 | ._* 3 | vendor 4 | .idea -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: [src/*] 3 | excluded_paths: [test/*] 4 | tools: 5 | external_code_coverage: 6 | timeout: 600 7 | runs: 3 8 | php_code_coverage: false -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 5.5 6 | - 5.4 7 | - 5.3 8 | - hhvm 9 | 10 | before_script: 11 | - composer self-update 12 | - composer install 13 | 14 | script: 15 | - phpunit --coverage-text --coverage-clover=coverage.clover 16 | 17 | after_script: 18 | - wget https://scrutinizer-ci.com/ocular.phar 19 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 20 | 21 | matrix: 22 | allow_failures: 23 | - php: hhvm -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nick Volgas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Volnix\CSRF 2 | 3 | [![Build Status](https://img.shields.io/travis/volnix/csrf.svg?style=flat-square)](https://travis-ci.org/volnix/csrf) [![Downloads](https://img.shields.io/packagist/dt/volnix/csrf.svg?style=flat-square)](https://packagist.org/packages/volnix/csrf) [![Latest Stable Version](https://img.shields.io/packagist/v/volnix/csrf.svg?style=flat-square)](https://packagist.org/packages/volnix/csrf) [![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/volnix/csrf.svg?style=flat-square)](https://scrutinizer-ci.com/g/volnix/csrf/?branch=master) 4 | 5 | 6 | CSRF protection library that compares provided token to session token to ensure request validity. Token values are stored in session and validated against that session store to verify the request. Tokens are changed on every request so ensure frequently changes and increase the difficulty in guessing the token value. 7 | 8 | ## Installation 9 | 10 | This package is installed via composer and is pulled in as the `volnix/csrf` package. 11 | 12 | ```json 13 | 14 | "require": { 15 | "volnix/csrf": "~1.0" 16 | } 17 | 18 | ``` 19 | 20 | ## Unit Tests 21 | 22 | The unit tests for this application live in the `./tests` directory. There is a test for each library in the security package. The PHPUnit xml file is in the root of the project (`./phpunit.xml`). 23 | 24 | ## Usage 25 | 26 | This library is used for preventing cross-site request forgery. Currently you can retrieve the token, a pre-built query string, or a pre-built hidden input tag. 27 | 28 | There are two main pieces to this library: 29 | 30 | 1. Injection of a CSRF token 31 | 2. Validation of the CSRF token 32 | 33 | #### 1. Injection of token 34 | 35 | There are a variety of ways to get your CSRF token into your form markup: 36 | 37 | Value only: 38 | 39 | ```php 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | ``` 50 | 51 | Hidden input string: 52 | 53 | ```php 54 | 55 |
56 | 57 | 58 | 59 |
60 | 61 | ``` 62 | 63 | Query string: 64 | 65 | ```php 66 | 67 |
68 | 69 | 70 |
71 | 72 | ``` 73 | 74 | If a different token name is desired, you may pass it in on any call that retrieves the token (`getToken()`, `getHiddenInputString()`, `getQueryString()`): 75 | 76 | ```php 77 | 78 |
79 | 80 | 81 | 82 |
83 | 84 | ``` 85 | 86 | #### 2. Validation of token 87 | 88 | To validate your token, just pass in your array of POST/GET/REQUEST data. If you have a custom token name, then there is an optional second argument for it. 89 | 90 | > **Note:** token validation is done using a constant-time comparison method to protect against timing attacks. 91 | 92 | Basic POST data validation: 93 | 94 | ```php 95 | 96 | // generic POST data 97 | if ( CSRF::validate($_POST) ) { 98 | // good token 99 | } else { 100 | // bad token 101 | } 102 | 103 | ``` 104 | 105 | Using Symfony's HTTP Foundation: 106 | 107 | ```php 108 | 109 | // symfony object 110 | $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals(); 111 | 112 | if ( CSRF::validate($request->request->all()) ) { 113 | // good token 114 | } else { 115 | // bad token 116 | } 117 | 118 | ``` 119 | 120 | Validating a custom-named token: 121 | 122 | ```php 123 | 124 | // validating with a custom token name 125 | if ( CSRF::validate($_POST, 'my_custom_name') ) { 126 | // good token 127 | } else { 128 | // bad token 129 | } 130 | 131 | ``` 132 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "volnix/csrf", 3 | "description": "CSRF protection library that compares provided token to session token to ensure request validity.", 4 | "license": "MIT", 5 | "homepage": "https://github.com/volnix/csrf", 6 | "authors": [ 7 | { 8 | "name": "Nick Volgas", 9 | "email": "nvolgas@ark.org" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "Volnix\\CSRF\\": "src/" 15 | } 16 | }, 17 | "require": { 18 | "php": ">= 5.3" 19 | }, 20 | 21 | "require-dev":{ 22 | "phpunit/phpunit": "~3.7" 23 | }, 24 | "minimum-stability": "dev" 25 | } 26 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "39cd19be040f552ea699734260d386ed", 8 | "content-hash": "d609693b320b15f2322430e0aa01a0a6", 9 | "packages": [], 10 | "packages-dev": [ 11 | { 12 | "name": "phpunit/php-code-coverage", 13 | "version": "1.2.x-dev", 14 | "source": { 15 | "type": "git", 16 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 17 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" 18 | }, 19 | "dist": { 20 | "type": "zip", 21 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 22 | "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", 23 | "shasum": "" 24 | }, 25 | "require": { 26 | "php": ">=5.3.3", 27 | "phpunit/php-file-iterator": ">=1.3.0@stable", 28 | "phpunit/php-text-template": ">=1.2.0@stable", 29 | "phpunit/php-token-stream": ">=1.1.3,<1.3.0" 30 | }, 31 | "require-dev": { 32 | "phpunit/phpunit": "3.7.*@dev" 33 | }, 34 | "suggest": { 35 | "ext-dom": "*", 36 | "ext-xdebug": ">=2.0.5" 37 | }, 38 | "type": "library", 39 | "extra": { 40 | "branch-alias": { 41 | "dev-master": "1.2.x-dev" 42 | } 43 | }, 44 | "autoload": { 45 | "classmap": [ 46 | "PHP/" 47 | ] 48 | }, 49 | "notification-url": "https://packagist.org/downloads/", 50 | "include-path": [ 51 | "" 52 | ], 53 | "license": [ 54 | "BSD-3-Clause" 55 | ], 56 | "authors": [ 57 | { 58 | "name": "Sebastian Bergmann", 59 | "email": "sb@sebastian-bergmann.de", 60 | "role": "lead" 61 | } 62 | ], 63 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 64 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 65 | "keywords": [ 66 | "coverage", 67 | "testing", 68 | "xunit" 69 | ], 70 | "time": "2014-09-02 10:13:14" 71 | }, 72 | { 73 | "name": "phpunit/php-file-iterator", 74 | "version": "dev-master", 75 | "source": { 76 | "type": "git", 77 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 78 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" 79 | }, 80 | "dist": { 81 | "type": "zip", 82 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 83 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 84 | "shasum": "" 85 | }, 86 | "require": { 87 | "php": ">=5.3.3" 88 | }, 89 | "type": "library", 90 | "extra": { 91 | "branch-alias": { 92 | "dev-master": "1.4.x-dev" 93 | } 94 | }, 95 | "autoload": { 96 | "classmap": [ 97 | "src/" 98 | ] 99 | }, 100 | "notification-url": "https://packagist.org/downloads/", 101 | "license": [ 102 | "BSD-3-Clause" 103 | ], 104 | "authors": [ 105 | { 106 | "name": "Sebastian Bergmann", 107 | "email": "sb@sebastian-bergmann.de", 108 | "role": "lead" 109 | } 110 | ], 111 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 112 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 113 | "keywords": [ 114 | "filesystem", 115 | "iterator" 116 | ], 117 | "time": "2015-06-21 13:08:43" 118 | }, 119 | { 120 | "name": "phpunit/php-text-template", 121 | "version": "1.2.1", 122 | "source": { 123 | "type": "git", 124 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 125 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 126 | }, 127 | "dist": { 128 | "type": "zip", 129 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 130 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 131 | "shasum": "" 132 | }, 133 | "require": { 134 | "php": ">=5.3.3" 135 | }, 136 | "type": "library", 137 | "autoload": { 138 | "classmap": [ 139 | "src/" 140 | ] 141 | }, 142 | "notification-url": "https://packagist.org/downloads/", 143 | "license": [ 144 | "BSD-3-Clause" 145 | ], 146 | "authors": [ 147 | { 148 | "name": "Sebastian Bergmann", 149 | "email": "sebastian@phpunit.de", 150 | "role": "lead" 151 | } 152 | ], 153 | "description": "Simple template engine.", 154 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 155 | "keywords": [ 156 | "template" 157 | ], 158 | "time": "2015-06-21 13:50:34" 159 | }, 160 | { 161 | "name": "phpunit/php-timer", 162 | "version": "1.0.7", 163 | "source": { 164 | "type": "git", 165 | "url": "https://github.com/sebastianbergmann/php-timer.git", 166 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" 167 | }, 168 | "dist": { 169 | "type": "zip", 170 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 171 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 172 | "shasum": "" 173 | }, 174 | "require": { 175 | "php": ">=5.3.3" 176 | }, 177 | "type": "library", 178 | "autoload": { 179 | "classmap": [ 180 | "src/" 181 | ] 182 | }, 183 | "notification-url": "https://packagist.org/downloads/", 184 | "license": [ 185 | "BSD-3-Clause" 186 | ], 187 | "authors": [ 188 | { 189 | "name": "Sebastian Bergmann", 190 | "email": "sb@sebastian-bergmann.de", 191 | "role": "lead" 192 | } 193 | ], 194 | "description": "Utility class for timing", 195 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 196 | "keywords": [ 197 | "timer" 198 | ], 199 | "time": "2015-06-21 08:01:12" 200 | }, 201 | { 202 | "name": "phpunit/php-token-stream", 203 | "version": "1.2.2", 204 | "source": { 205 | "type": "git", 206 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 207 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" 208 | }, 209 | "dist": { 210 | "type": "zip", 211 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", 212 | "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", 213 | "shasum": "" 214 | }, 215 | "require": { 216 | "ext-tokenizer": "*", 217 | "php": ">=5.3.3" 218 | }, 219 | "type": "library", 220 | "extra": { 221 | "branch-alias": { 222 | "dev-master": "1.2-dev" 223 | } 224 | }, 225 | "autoload": { 226 | "classmap": [ 227 | "PHP/" 228 | ] 229 | }, 230 | "notification-url": "https://packagist.org/downloads/", 231 | "include-path": [ 232 | "" 233 | ], 234 | "license": [ 235 | "BSD-3-Clause" 236 | ], 237 | "authors": [ 238 | { 239 | "name": "Sebastian Bergmann", 240 | "email": "sb@sebastian-bergmann.de", 241 | "role": "lead" 242 | } 243 | ], 244 | "description": "Wrapper around PHP's tokenizer extension.", 245 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 246 | "keywords": [ 247 | "tokenizer" 248 | ], 249 | "time": "2014-03-03 05:10:30" 250 | }, 251 | { 252 | "name": "phpunit/phpunit", 253 | "version": "3.7.x-dev", 254 | "source": { 255 | "type": "git", 256 | "url": "https://github.com/sebastianbergmann/phpunit.git", 257 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" 258 | }, 259 | "dist": { 260 | "type": "zip", 261 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", 262 | "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", 263 | "shasum": "" 264 | }, 265 | "require": { 266 | "ext-ctype": "*", 267 | "ext-dom": "*", 268 | "ext-json": "*", 269 | "ext-pcre": "*", 270 | "ext-reflection": "*", 271 | "ext-spl": "*", 272 | "php": ">=5.3.3", 273 | "phpunit/php-code-coverage": "~1.2", 274 | "phpunit/php-file-iterator": "~1.3", 275 | "phpunit/php-text-template": "~1.1", 276 | "phpunit/php-timer": "~1.0", 277 | "phpunit/phpunit-mock-objects": "~1.2", 278 | "symfony/yaml": "~2.0" 279 | }, 280 | "require-dev": { 281 | "pear-pear.php.net/pear": "1.9.4" 282 | }, 283 | "suggest": { 284 | "phpunit/php-invoker": "~1.1" 285 | }, 286 | "bin": [ 287 | "composer/bin/phpunit" 288 | ], 289 | "type": "library", 290 | "extra": { 291 | "branch-alias": { 292 | "dev-master": "3.7.x-dev" 293 | } 294 | }, 295 | "autoload": { 296 | "classmap": [ 297 | "PHPUnit/" 298 | ] 299 | }, 300 | "notification-url": "https://packagist.org/downloads/", 301 | "include-path": [ 302 | "", 303 | "../../symfony/yaml/" 304 | ], 305 | "license": [ 306 | "BSD-3-Clause" 307 | ], 308 | "authors": [ 309 | { 310 | "name": "Sebastian Bergmann", 311 | "email": "sebastian@phpunit.de", 312 | "role": "lead" 313 | } 314 | ], 315 | "description": "The PHP Unit Testing framework.", 316 | "homepage": "http://www.phpunit.de/", 317 | "keywords": [ 318 | "phpunit", 319 | "testing", 320 | "xunit" 321 | ], 322 | "time": "2014-10-17 09:04:17" 323 | }, 324 | { 325 | "name": "phpunit/phpunit-mock-objects", 326 | "version": "1.2.x-dev", 327 | "source": { 328 | "type": "git", 329 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 330 | "reference": "c39c4511c3b007539eb170c32cbc2af49a07351a" 331 | }, 332 | "dist": { 333 | "type": "zip", 334 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c39c4511c3b007539eb170c32cbc2af49a07351a", 335 | "reference": "c39c4511c3b007539eb170c32cbc2af49a07351a", 336 | "shasum": "" 337 | }, 338 | "require": { 339 | "php": ">=5.3.3", 340 | "phpunit/php-text-template": ">=1.1.1@stable" 341 | }, 342 | "require-dev": { 343 | "phpunit/phpunit": "3.7.*@dev" 344 | }, 345 | "suggest": { 346 | "ext-soap": "*" 347 | }, 348 | "type": "library", 349 | "extra": { 350 | "branch-alias": { 351 | "dev-master": "1.2.x-dev" 352 | } 353 | }, 354 | "autoload": { 355 | "classmap": [ 356 | "PHPUnit/" 357 | ] 358 | }, 359 | "notification-url": "https://packagist.org/downloads/", 360 | "include-path": [ 361 | "" 362 | ], 363 | "license": [ 364 | "BSD-3-Clause" 365 | ], 366 | "authors": [ 367 | { 368 | "name": "Sebastian Bergmann", 369 | "email": "sb@sebastian-bergmann.de", 370 | "role": "lead" 371 | } 372 | ], 373 | "description": "Mock Object library for PHPUnit", 374 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 375 | "keywords": [ 376 | "mock", 377 | "xunit" 378 | ], 379 | "time": "2014-02-16 12:43:56" 380 | }, 381 | { 382 | "name": "symfony/yaml", 383 | "version": "2.8.x-dev", 384 | "source": { 385 | "type": "git", 386 | "url": "https://github.com/symfony/yaml.git", 387 | "reference": "f65177d7093bc29aefebfbdbe496b9e3a6292653" 388 | }, 389 | "dist": { 390 | "type": "zip", 391 | "url": "https://api.github.com/repos/symfony/yaml/zipball/f65177d7093bc29aefebfbdbe496b9e3a6292653", 392 | "reference": "f65177d7093bc29aefebfbdbe496b9e3a6292653", 393 | "shasum": "" 394 | }, 395 | "require": { 396 | "php": ">=5.3.9" 397 | }, 398 | "type": "library", 399 | "extra": { 400 | "branch-alias": { 401 | "dev-master": "2.8-dev" 402 | } 403 | }, 404 | "autoload": { 405 | "psr-4": { 406 | "Symfony\\Component\\Yaml\\": "" 407 | }, 408 | "exclude-from-classmap": [ 409 | "/Tests/" 410 | ] 411 | }, 412 | "notification-url": "https://packagist.org/downloads/", 413 | "license": [ 414 | "MIT" 415 | ], 416 | "authors": [ 417 | { 418 | "name": "Fabien Potencier", 419 | "email": "fabien@symfony.com" 420 | }, 421 | { 422 | "name": "Symfony Community", 423 | "homepage": "https://symfony.com/contributors" 424 | } 425 | ], 426 | "description": "Symfony Yaml Component", 427 | "homepage": "https://symfony.com", 428 | "time": "2015-11-18 13:45:00" 429 | } 430 | ], 431 | "aliases": [], 432 | "minimum-stability": "dev", 433 | "stability-flags": [], 434 | "prefer-stable": false, 435 | "prefer-lowest": false, 436 | "platform": { 437 | "php": ">= 5.3" 438 | }, 439 | "platform-dev": [] 440 | } 441 | -------------------------------------------------------------------------------- /phpunit.php: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | 21 | ./vendor 22 | 23 | 24 | src 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/CSRF.php: -------------------------------------------------------------------------------- 1 | ', $token_name, static::getToken($token_name)); 90 | } 91 | 92 | /** 93 | * Get a query string mark-up with the token/token name in it. 94 | * 95 | * @param string $token_name - defaults to the default token name 96 | * @return string 97 | */ 98 | public static function getQueryString($token_name = self::TOKEN_NAME) 99 | { 100 | return sprintf('%s=%s', $token_name, static::getToken($token_name)); 101 | } 102 | 103 | /** 104 | * Get an array with the token (useful for form libraries, etc.) 105 | * 106 | * @param string $token_name 107 | * @return array 108 | */ 109 | public static function getTokenAsArray($token_name = self::TOKEN_NAME) 110 | { 111 | return array( 112 | $token_name => self::getToken($token_name) 113 | ); 114 | } 115 | 116 | /** 117 | * Constant-time string comparison. This comparison function is timing-attack safe 118 | * 119 | * @param string $hasha 120 | * @param string $hashb 121 | * @return bool 122 | */ 123 | public static function compare($hasha = "", $hashb = "") 124 | { 125 | // we want hashes_are_not_equal to be false by the end of this if the strings are identical 126 | 127 | // if the strings are NOT equal length this will return true, else false 128 | $hashes_are_not_equal = strlen($hasha) ^ strlen($hashb); 129 | 130 | // compare the shortest of the two strings (the above line will still kick back a failure if the lengths weren't equal. this just keeps us from over-flowing our strings when comparing 131 | $length = min(strlen($hasha), strlen($hashb)); 132 | $hasha = substr($hasha, 0, $length); 133 | $hashb = substr($hashb, 0, $length); 134 | 135 | // iterate through the hashes comparing them character by character 136 | // if a character does not match, then return true, so the hashes are not equal 137 | for ($i = 0; $i < strlen($hasha); $i++) { 138 | $hashes_are_not_equal += !(ord($hasha[$i]) === ord($hashb[$i])); 139 | } 140 | 141 | // if not hashes are not equal, then hashes are equal 142 | return !$hashes_are_not_equal; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /tests/CSRF.php: -------------------------------------------------------------------------------- 1 | _killSession(); 26 | } 27 | 28 | public function tearDown() 29 | { 30 | $this->_killSession(); 31 | session_write_close(); 32 | } 33 | 34 | public function testGenerateToken() 35 | { 36 | CSRFTokenGenerator::generateToken(); 37 | $this->assertNotNull($_SESSION[CSRFTokenGenerator::TOKEN_NAME]); 38 | 39 | CSRFTokenGenerator::generateToken(self::ALT_TOKEN_NAME); 40 | $this->assertNotNull($_SESSION[self::ALT_TOKEN_NAME]); 41 | } 42 | 43 | public function testGetToken() 44 | { 45 | // basic 46 | CSRFTokenGenerator::generateToken(); 47 | $this->assertEquals($_SESSION[CSRFTokenGenerator::TOKEN_NAME], CSRFTokenGenerator::getToken()); 48 | 49 | CSRFTokenGenerator::generateToken(self::ALT_TOKEN_NAME); 50 | $this->assertEquals($_SESSION[self::ALT_TOKEN_NAME], CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME)); 51 | 52 | $this->_killSession(); 53 | 54 | // no token set, should get set without explicit generate call 55 | $this->assertNotNull(CSRFTokenGenerator::getToken()); 56 | $this->assertNotNull(CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME)); 57 | 58 | $this->assertEquals($_SESSION[CSRFTokenGenerator::TOKEN_NAME], CSRFTokenGenerator::getToken()); 59 | $this->assertEquals($_SESSION[self::ALT_TOKEN_NAME], CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME)); 60 | } 61 | 62 | public function testValidate() 63 | { 64 | // good validation 65 | $post_data = array(CSRFTokenGenerator::TOKEN_NAME => CSRFTokenGenerator::getToken()); 66 | $this->assertTrue(CSRFTokenGenerator::validate($post_data)); 67 | 68 | $post_data = array(self::ALT_TOKEN_NAME => CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME)); 69 | $this->assertTrue(CSRFTokenGenerator::validate($post_data, self::ALT_TOKEN_NAME)); 70 | 71 | // bad validation 72 | $this->_killSession(); 73 | 74 | $post_data = array(CSRFTokenGenerator::TOKEN_NAME => "bad_token_data"); 75 | $this->assertFalse(CSRFTokenGenerator::validate($post_data)); 76 | 77 | $post_data = array(self::ALT_TOKEN_NAME => "bad_token_data"); 78 | $this->assertFalse(CSRFTokenGenerator::validate($post_data, self::ALT_TOKEN_NAME)); 79 | 80 | $post_data = array("bad_token_name" => CSRFTokenGenerator::getToken()); 81 | $this->assertFalse(CSRFTokenGenerator::validate($post_data)); 82 | } 83 | 84 | public function testGetHiddenInput() 85 | { 86 | $token = CSRFTokenGenerator::getToken(); 87 | $this->assertEquals(sprintf('', CSRFTokenGenerator::TOKEN_NAME, $token), CSRFTokenGenerator::getHiddenInputString()); 88 | 89 | $token = CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME); 90 | $this->assertEquals(sprintf('', self::ALT_TOKEN_NAME, $token), CSRFTokenGenerator::getHiddenInputString(self::ALT_TOKEN_NAME)); 91 | } 92 | 93 | public function testGetQueryString() 94 | { 95 | $token = CSRFTokenGenerator::getToken(); 96 | $this->assertEquals(sprintf('%s=%s', CSRFTokenGenerator::TOKEN_NAME, $token), CSRFTokenGenerator::getQueryString()); 97 | 98 | $token = CSRFTokenGenerator::getToken(self::ALT_TOKEN_NAME); 99 | $this->assertEquals(sprintf('%s=%s', self::ALT_TOKEN_NAME, $token), CSRFTokenGenerator::getQueryString(self::ALT_TOKEN_NAME)); 100 | } 101 | 102 | public function testGetAsArray() 103 | { 104 | $token = CSRFTokenGenerator::getToken(); 105 | 106 | } 107 | 108 | private function _killSession() 109 | { 110 | $_SESSION[CSRFTokenGenerator::TOKEN_NAME] = $_SESSION[self::ALT_TOKEN_NAME] = null; 111 | unset($_SESSION[CSRFTokenGenerator::TOKEN_NAME], $_SESSION[self::ALT_TOKEN_NAME]); 112 | } 113 | } 114 | --------------------------------------------------------------------------------