15
15
*/
16
16
class JWT
17
17
{
18
- public static $ only_method = 'HS256 ' ;
19
-
20
- public static $ methods = array (
18
+ public static $ supported_algs = array (
21
19
'HS256 ' => array ('hash_hmac ' , 'SHA256 ' ),
22
20
'HS512 ' => array ('hash_hmac ' , 'SHA512 ' ),
23
21
'HS384 ' => array ('hash_hmac ' , 'SHA384 ' ),
@@ -27,9 +25,9 @@ class JWT
27
25
/**
28
26
* Decodes a JWT string into a PHP object.
29
27
*
30
- * @param string $jwt The JWT
31
- * @param string|Array|null $key The secret key, or map of keys
32
- * @param bool $verify Don't skip verification process
28
+ * @param string $jwt The JWT
29
+ * @param string|Array|null $key The secret key, or map of keys
30
+ * @param Array $allowed_algs List of supported verification algorithms
33
31
*
34
32
* @return object The JWT's payload as a PHP object
35
33
*
@@ -43,7 +41,7 @@ class JWT
43
41
* @uses jsonDecode
44
42
* @uses urlsafeB64Decode
45
43
*/
46
- public static function decode ($ jwt , $ key = null , $ verify = true )
44
+ public static function decode ($ jwt , $ key = null , $ allowed_algs = array () )
47
45
{
48
46
$ tks = explode ('. ' , $ jwt );
49
47
if (count ($ tks ) != 3 ) {
@@ -57,10 +55,16 @@ public static function decode($jwt, $key = null, $verify = true)
57
55
throw new UnexpectedValueException ('Invalid claims encoding ' );
58
56
}
59
57
$ sig = JWT ::urlsafeB64Decode ($ cryptob64 );
60
- if ($ verify ) {
58
+ if (isset ( $ key ) ) {
61
59
if (empty ($ header ->alg )) {
62
60
throw new DomainException ('Empty algorithm ' );
63
61
}
62
+ if (empty (self ::$ supported_algs [$ header ->alg ])) {
63
+ throw new DomainException ('Algorithm not supported ' );
64
+ }
65
+ if (!is_array ($ allowed_algs ) || !in_array ($ header ->alg , $ allowed_algs )) {
66
+ throw new DomainException ('Algorithm not allowed ' );
67
+ }
64
68
if (is_array ($ key )) {
65
69
if (isset ($ header ->kid )) {
66
70
$ key = $ key [$ header ->kid ];
@@ -105,16 +109,16 @@ public static function decode($jwt, $key = null, $verify = true)
105
109
*
106
110
* @param object|array $payload PHP object or array
107
111
* @param string $key The secret key
108
- * @param string $algo The signing algorithm. Supported
112
+ * @param string $alg The signing algorithm. Supported
109
113
* algorithms are 'HS256', 'HS384' and 'HS512'
110
114
*
111
115
* @return string A signed JWT
112
116
* @uses jsonEncode
113
117
* @uses urlsafeB64Encode
114
118
*/
115
- public static function encode ($ payload , $ key , $ algo = 'HS256 ' , $ keyId = null )
119
+ public static function encode ($ payload , $ key , $ alg = 'HS256 ' , $ keyId = null )
116
120
{
117
- $ header = array ('typ ' => 'JWT ' , 'alg ' => $ algo );
121
+ $ header = array ('typ ' => 'JWT ' , 'alg ' => $ alg );
118
122
if ($ keyId !== null ) {
119
123
$ header ['kid ' ] = $ keyId ;
120
124
}
@@ -123,7 +127,7 @@ public static function encode($payload, $key, $algo = 'HS256', $keyId = null)
123
127
$ segments [] = JWT ::urlsafeB64Encode (JWT ::jsonEncode ($ payload ));
124
128
$ signing_input = implode ('. ' , $ segments );
125
129
126
- $ signature = JWT ::sign ($ signing_input , $ key , $ algo );
130
+ $ signature = JWT ::sign ($ signing_input , $ key , $ alg );
127
131
$ segments [] = JWT ::urlsafeB64Encode ($ signature );
128
132
129
133
return implode ('. ' , $ segments );
@@ -134,24 +138,24 @@ public static function encode($payload, $key, $algo = 'HS256', $keyId = null)
134
138
*
135
139
* @param string $msg The message to sign
136
140
* @param string|resource $key The secret key
137
- * @param string $method The signing algorithm. Supported algorithms
141
+ * @param string $alg The signing algorithm. Supported algorithms
138
142
* are 'HS256', 'HS384', 'HS512' and 'RS256'
139
143
*
140
144
* @return string An encrypted message
141
145
* @throws DomainException Unsupported algorithm was specified
142
146
*/
143
- public static function sign ($ msg , $ key , $ method = 'HS256 ' )
147
+ public static function sign ($ msg , $ key , $ alg = 'HS256 ' )
144
148
{
145
- if (empty (self ::$ methods [ $ method ])) {
149
+ if (empty (self ::$ supported_algs [ $ alg ])) {
146
150
throw new DomainException ('Algorithm not supported ' );
147
151
}
148
- list ($ function , $ algo ) = self ::$ methods [ $ method ];
152
+ list ($ function , $ algorithm ) = self ::$ supported_algs [ $ alg ];
149
153
switch ($ function ) {
150
154
case 'hash_hmac ' :
151
- return hash_hmac ($ algo , $ msg , $ key , true );
155
+ return hash_hmac ($ algorithm , $ msg , $ key , true );
152
156
case 'openssl ' :
153
157
$ signature = '' ;
154
- $ success = openssl_sign ($ msg , $ signature , $ key , $ algo );
158
+ $ success = openssl_sign ($ msg , $ signature , $ key , $ algorithm );
155
159
if (!$ success ) {
156
160
throw new DomainException ("OpenSSL unable to sign data " );
157
161
} else {
@@ -166,32 +170,28 @@ public static function sign($msg, $key, $method = 'HS256')
166
170
* @param string $msg the original message
167
171
* @param string $signature
168
172
* @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key
169
- * @param string $method
173
+ * @param string $alg
170
174
* @return bool
171
175
* @throws DomainException Invalid Algorithm or OpenSSL failure
172
176
*/
173
- public static function verify ($ msg , $ signature , $ key , $ method = ' HS256 ' )
177
+ private static function verify ($ msg , $ signature , $ key , $ alg )
174
178
{
175
- if (empty (self ::$ methods [ $ method ])) {
179
+ if (empty (self ::$ supported_algs [ $ alg ])) {
176
180
throw new DomainException ('Algorithm not supported ' );
177
181
}
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
- }
183
- list ($ function , $ algo ) = self ::$ methods [$ method ];
182
+
183
+ list ($ function , $ algorithm ) = self ::$ supported_algs [$ alg ];
184
184
switch ($ function ) {
185
185
case 'openssl ' :
186
- $ success = openssl_verify ($ msg , $ signature , $ key , $ algo );
186
+ $ success = openssl_verify ($ msg , $ signature , $ key , $ algorithm );
187
187
if (!$ success ) {
188
188
throw new DomainException ("OpenSSL unable to verify data: " . openssl_error_string ());
189
189
} else {
190
190
return $ signature ;
191
191
}
192
192
case 'hash_hmac ' :
193
193
default :
194
- $ hash = hash_hmac ($ algo , $ msg , $ key , true );
194
+ $ hash = hash_hmac ($ algorithm , $ msg , $ key , true );
195
195
if (function_exists ('hash_equals ' )) {
196
196
return hash_equals ($ signature , $ hash );
197
197
}
@@ -309,7 +309,7 @@ private static function handleJsonError($errno)
309
309
: 'Unknown JSON error: ' . $ errno
310
310
);
311
311
}
312
-
312
+
313
313
/**
314
314
* Get the number of bytes in cryptographic strings.
315
315
*
@@ -323,22 +323,4 @@ private static function safeStrlen($str)
323
323
}
324
324
return strlen ($ str );
325
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
- }
344
326
}
0 commit comments