15
15
*/
16
16
class JWT
17
17
{
18
+ public static $ only_method = 'HS256 ' ;
19
+
18
20
public static $ methods = array (
19
21
'HS256 ' => array ('hash_hmac ' , 'SHA256 ' ),
20
22
'HS512 ' => array ('hash_hmac ' , 'SHA512 ' ),
@@ -173,6 +175,11 @@ public static function verify($msg, $signature, $key, $method = 'HS256')
173
175
if (empty (self ::$ methods [$ method ])) {
174
176
throw new DomainException ('Algorithm not supported ' );
175
177
}
178
+ if (self ::$ only_method === null ) {
179
+ throw new DomainException ('Algorithm not specified ' );
180
+ } elseif ($ method !== self ::$ only_method ) {
181
+ throw new DomainException ('Incorrect algorithm error ' );
182
+ }
176
183
list ($ function , $ algo ) = self ::$ methods [$ method ];
177
184
switch ($ function ) {
178
185
case 'openssl ' :
@@ -185,13 +192,16 @@ public static function verify($msg, $signature, $key, $method = 'HS256')
185
192
case 'hash_hmac ' :
186
193
default :
187
194
$ hash = hash_hmac ($ algo , $ msg , $ key , true );
188
- $ len = min (strlen ($ signature ), strlen ($ hash ));
195
+ if (function_exists ('hash_equals ' )) {
196
+ return hash_equals ($ signature , $ hash );
197
+ }
198
+ $ len = min (self ::safeStrlen ($ signature ), self ::safeStrlen ($ hash ));
189
199
190
200
$ status = 0 ;
191
201
for ($ i = 0 ; $ i < $ len ; $ i ++) {
192
202
$ status |= (ord ($ signature [$ i ]) ^ ord ($ hash [$ i ]));
193
203
}
194
- $ status |= (strlen ($ signature ) ^ strlen ($ hash ));
204
+ $ status |= (self :: safeStrlen ($ signature ) ^ self :: safeStrlen ($ hash ));
195
205
196
206
return ($ status === 0 );
197
207
}
@@ -299,4 +309,36 @@ private static function handleJsonError($errno)
299
309
: 'Unknown JSON error: ' . $ errno
300
310
);
301
311
}
312
+
313
+ /**
314
+ * Get the number of bytes in cryptographic strings.
315
+ *
316
+ * @param string
317
+ * @return int
318
+ */
319
+ private static function safeStrlen ($ str )
320
+ {
321
+ if (function_exists ('mb_strlen ' )) {
322
+ return mb_strlen ($ str , '8bit ' );
323
+ }
324
+ return strlen ($ str );
325
+ }
326
+
327
+ /**
328
+ * Set the only allowed method for this server.
329
+ *
330
+ * @ref https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
331
+ *
332
+ * @param string $method array index in self::$methods
333
+ *
334
+ * @return boolean
335
+ */
336
+ public static function setOnlyAllowedMethod ($ method )
337
+ {
338
+ if (!empty (self ::$ methods [$ method ])) {
339
+ self ::$ only_method = $ method ;
340
+ return true ;
341
+ }
342
+ return false ;
343
+ }
302
344
}
0 commit comments