1 <?php
2
3 4 5 6 7 8 9
10 class rex_csrf_token
11 {
12 use rex_factory_trait;
13
14 const PARAM = '_csrf_token';
15
16 private $id;
17
18 private function __construct($tokenId)
19 {
20 $this->id = $tokenId;
21 }
22
23 24 25 26 27
28 public static function factory($tokenId)
29 {
30 $class = static::getFactoryClass();
31
32 return new $class($tokenId);
33 }
34
35 36 37
38 public function getId()
39 {
40 return $this->id;
41 }
42
43 44 45
46 public function getValue()
47 {
48 $tokens = self::getTokens();
49
50 if (isset($tokens[$this->id])) {
51 return $tokens[$this->id];
52 }
53
54 $token = self::generateToken();
55 $tokens[$this->id] = $token;
56 rex_set_session(self::getSessionKey(), $tokens);
57
58 return $token;
59 }
60
61 62 63
64 public function getHiddenField()
65 {
66 return sprintf('<input type="hidden" name="%s" value="%s"/>', self::PARAM, $this->getValue());
67 }
68
69 70 71 72 73
74 public function getUrlParams()
75 {
76 return [self::PARAM => $this->getValue()];
77 }
78
79 80 81
82 public function isValid()
83 {
84 $tokens = self::getTokens();
85
86 if (!isset($tokens[$this->id])) {
87 return false;
88 }
89
90 $token = rex_request(self::PARAM, 'string');
91
92 return hash_equals($tokens[$this->id], $token);
93 }
94
95 public function remove()
96 {
97 $tokens = self::getTokens();
98
99 if (!isset($tokens[$this->id])) {
100 return;
101 }
102
103 unset($tokens[$this->id]);
104
105 rex_set_session(self::getSessionKey(), $tokens);
106 }
107
108 public static function removeAll()
109 {
110 rex_login::startSession();
111
112 rex_unset_session(self::getBaseSessionKey());
113 rex_unset_session(self::getBaseSessionKey().'_https');
114 }
115
116 private static function getTokens()
117 {
118 rex_login::startSession();
119
120 return rex_session(self::getSessionKey(), 'array');
121 }
122
123 private static function getSessionKey()
124 {
125
126
127 $suffix = rex_request::isHttps() ? '_https' : '';
128
129 return self::getBaseSessionKey().$suffix;
130 }
131
132 private static function getBaseSessionKey()
133 {
134 return 'csrf_tokens_'.rex::getEnvironment();
135 }
136
137 private static function generateToken()
138 {
139 $bytes = random_bytes(32);
140
141 return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
142 }
143 }
144