1: <?php
2:
3: namespace ModHelper;
4:
5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Nonce
15: {
16: 17: 18:
19: private $hash;
20:
21: 22: 23:
24: private $key;
25:
26: 27: 28:
29: private $ttl = 900;
30:
31: 32: 33: 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: 47: 48: 49: 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:
62: $this->hash = $_SESSION['csrf_' . $this->key];
63:
64:
65: $_SESSION['csrf_' . $this->key] = null;
66:
67:
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:
73: if ($_POST[$this->key] != $this->hash) {
74: throw new Exceptions\BadCombinationException('Invalid CSRF token.');
75: }
76:
77:
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: 87:
88: public function getHash()
89: {
90: return $this->hash;
91: }
92:
93: 94: 95:
96: public function setKey($key)
97: {
98: $this->key = $key;
99: }
100:
101: 102: 103:
104: public function getKey()
105: {
106: return $this->key;
107: }
108:
109: 110: 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: 122:
123: public function getTtl()
124: {
125: return $this->ttl;
126: }
127:
128: 129: 130: 131: 132:
133: public function generate()
134: {
135:
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: 141: 142: 143: 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: