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