1515 */
1616class JWT
1717{
18+ public static $ only_method = 'HS256 ' ;
19+
1820 public static $ methods = array (
1921 'HS256 ' => array ('hash_hmac ' , 'SHA256 ' ),
2022 'HS512 ' => array ('hash_hmac ' , 'SHA512 ' ),
@@ -173,6 +175,11 @@ public static function verify($msg, $signature, $key, $method = 'HS256')
173175 if (empty (self ::$ methods [$ method ])) {
174176 throw new DomainException ('Algorithm not supported ' );
175177 }
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+ }
176183 list ($ function , $ algo ) = self ::$ methods [$ method ];
177184 switch ($ function ) {
178185 case 'openssl ' :
@@ -185,13 +192,16 @@ public static function verify($msg, $signature, $key, $method = 'HS256')
185192 case 'hash_hmac ' :
186193 default :
187194 $ 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 ));
189199
190200 $ status = 0 ;
191201 for ($ i = 0 ; $ i < $ len ; $ i ++) {
192202 $ status |= (ord ($ signature [$ i ]) ^ ord ($ hash [$ i ]));
193203 }
194- $ status |= (strlen ($ signature ) ^ strlen ($ hash ));
204+ $ status |= (self :: safeStrlen ($ signature ) ^ self :: safeStrlen ($ hash ));
195205
196206 return ($ status === 0 );
197207 }
@@ -299,4 +309,36 @@ private static function handleJsonError($errno)
299309 : 'Unknown JSON error: ' . $ errno
300310 );
301311 }
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+ }
302344}
0 commit comments