Overview

Namespaces

  • ModHelper
    • Exceptions

Classes

  • ModHelper\A
  • ModHelper\BitwiseFlag
  • ModHelper\Collection
  • ModHelper\Database
  • ModHelper\Editor
  • ModHelper\Hooks
  • ModHelper\Linktree
  • ModHelper\Menu
  • ModHelper\Nonce
  • ModHelper\Psr4AutoloaderClass
  • ModHelper\Verify

Traits

  • ModHelper\SingletonTrait

Exceptions

  • ModHelper\Exceptions\BadCombinationException
  • ModHelper\Exceptions\MissingDataException
  • ModHelper\Exceptions\ValidationException
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: namespace ModHelper;
  4: 
  5: /**
  6:  * Nonce, an anti CSRF token generation/checking class.
  7:  * Copyright (c) 2011 Thibaut Despoulain <http://bkcore.com/blog/code/nocsrf-php-class.html>
  8:  * @copyright Copyright (c) 2015 John Rayes
  9:  * @license http://opensource.org/licenses/MIT MIT
 10:  *
 11:  * @package ModHelper
 12:  * @version 1.0
 13:  */
 14: class Nonce
 15: {
 16:     /**
 17:      * @var string
 18:      */
 19:     private $hash;
 20: 
 21:     /**
 22:      * @var string
 23:      */
 24:     private $key;
 25: 
 26:     /**
 27:      * @var int
 28:      */
 29:     private $ttl = 900;
 30: 
 31:     /**
 32:      * @param string $key The session and $origin key where to find the token.
 33:      * @param int $ttl (Facultative) Makes the token expire after $this->ttl seconds. (null = never)
 34:      */
 35:     public function __construct($key = null, $ttl = 900)
 36:     {
 37:         if (!isset($this->key)) {
 38:             $this->key = $this->randomString(8);
 39:         }
 40:         if (!is_int($ttl)) {
 41:             throw new \InvalidArgumentException('Integer expected: $ttl');
 42:         }
 43:         $this->ttl = $ttl;
 44:     }
 45:     /**
 46:      * Check CSRF tokens match between session and $origin.
 47:      * Make sure you generated a token in the form before checking it.
 48:      *
 49:      * @return bool Returns FALSE if a CSRF attack is detected, TRUE otherwise.
 50:      */
 51:     public function check()
 52:     {
 53:         if (!isset($_SESSION['csrf_' . $this->key])) {
 54:             throw new Exceptions\MissingDataException('Missing CSRF session token.');
 55:         }
 56: 
 57:         if (!isset($_POST[$this->key])) {
 58:             throw new Exceptions\MissingDataException('Missing CSRF form token.');
 59:         }
 60: 
 61:         // Get valid token from session
 62:         $this->hash = $_SESSION['csrf_' . $this->key];
 63: 
 64:         // Free up session token for one-time CSRF token usage.
 65:         $_SESSION['csrf_' . $this->key] = null;
 66: 
 67:         // Origin checks
 68:         if (sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) != substr(base64_decode($this->hash), 10, 40)) {
 69:             throw new Exceptions\BadCombinationException('Form origin does not match token origin.');
 70:         }
 71: 
 72:         // Check if session token matches form token
 73:         if ($_POST[$this->key] != $this->hash) {
 74:             throw new Exceptions\BadCombinationException('Invalid CSRF token.');
 75:         }
 76: 
 77:         // Check for token expiration
 78:         if ($this->ttl != null && is_int($this->ttl) && intval(substr(base64_decode($this->hash), 0, 10)) + $this->ttl < time()) {
 79:             throw new \RangeException('CSRF token has expired.');
 80:         }
 81: 
 82:         return true;
 83:     }
 84: 
 85:     /**
 86:      * @return string
 87:      */
 88:     public function getHash()
 89:     {
 90:         return $this->hash;
 91:     }
 92: 
 93:     /**
 94:      * @param string $key
 95:      */
 96:     public function setKey($key)
 97:     {
 98:         $this->key = $key;
 99:     }
100: 
101:     /**
102:      * @return string
103:      */
104:     public function getKey()
105:     {
106:         return $this->key;
107:     }
108: 
109:     /**
110:      * @param int $ttl
111:      */
112:     public function setTtl($ttl)
113:     {
114:         if (!is_int($ttl)) {
115:             throw new \InvalidArgumentException('Integer expected: $ttl');
116:         }
117:         $this->ttl = $ttl;
118:     }
119: 
120:     /**
121:      * @return int
122:      */
123:     public function getTtl()
124:     {
125:         return $this->ttl;
126:     }
127: 
128:     /**
129:      * CSRF token generator. After generating the token, put it inside a hidden form field named $this->key.
130:      *
131:      * @return string The generated, base64 encoded token.
132:      */
133:     public function generate()
134:     {
135:         // token generation (basically base64_encode any random complex string, time() is used for token expiration)
136:         return $_SESSION['csrf_' . $this->key] = $this->hash = base64_encode(time() . sha1($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) . $this->randomString(32));
137:     }
138: 
139:     /**
140:      * Generates a random string of given $length.
141:      *
142:      * @param int $length The string length.
143:      * @return string The randomly generated string.
144:      */
145:     private function randomString($length)
146:     {
147:         if (!is_int($length)) {
148:             throw new \InvalidArgumentException('Integer expected: $length');
149:         }
150:         $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijqlmnopqrtsuvwxyz0123456789';
151:         $max = strlen($seed) - 1;
152: 
153:         $string = '';
154:         for ($i = 0; $i < $length; ++$i) {
155:             $string .= $seed{intval(mt_rand(0.0, $max))};
156:         }
157: 
158:         return $string;
159:     }
160: }
161: 
162: 
API documentation generated by ApiGen