PHP 中的自定义 JWT 一直说签名无效

Posted

技术标签:

【中文标题】PHP 中的自定义 JWT 一直说签名无效【英文标题】:Custom JWT IN PHP keeps saying Invalid signature 【发布时间】:2020-01-23 23:54:22 【问题描述】:

我是新手,我正在尽力创建自己的 JWT 类。我认为我做的一切都是正确的,但是当我尝试将我的令牌粘贴到 jwt.io 中时,它一直说签名无效。我不禁觉得我要么错过了什么愚蠢的东西,要么有什么不对劲。

我的代码如下:

class Jwt

protected $header;

protected $payload;

protected $signature;

protected $secret;

protected $alg;

protected $jwt;

function __construct($header, $payload, $secret)

$this->SetHeader($header);
$this->alg = $header['alg'];
$this->SetPayload($payload);
$this->secret = $secret;
$this->SetSignature();


public function SetHeader($header)
$this->header = str_replace(["+", "/", "="],
['-', '_',""],
base64_encode(json_encode($header)));   


public function SetPayload($payload)

$this->payload = 
str_replace(["+", "/", "="],
['-',   '_',""],
base64_encode(json_encode($payload)));  


public function SetSignature()

$data = $this->header.".".$this->payload;
$this->alg = str_replace('HS', 'sha', $this->alg);
$hashedData = hash_hmac($this->alg, $data , $this->secret, true);
$this->signature = str_replace(
["+", "/", "="], ['-', '_', ""],   base64_encode($hashedData)
);


public function SetJwt()

$this->jwt = $this->header.'.'.$this->payload.'.'.$this->signature;


public function GetJwt()

return $this->jwt;

在我的 Index.php 中:

use root\lib\Jwt;
$myFavorites = 
['element' => 'Sun', 'animal' => 'Leopard','color'=>'Orange'];
$secret = bin2hex(random_bytes(32));

$jwt = new Jwt
(['alg' => 'HS256', 'typ' => 'JWT'], $myFavorites, $secret)
$jwt->SetJwt();

var_dump($jwt->GetJwt());

一切正常,调试器显示正确的输出,但不知何故它只是说无效签名。

如果我更改 jwt.io 网站上的算法,它会起作用。所以我猜它与签名或算法有关

我正在从 var_dump 的屏幕输出中复制它,这可能是原因吗?

新令牌是:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbGVtZW50IjoiU3VuIiwiYW5pbWFsIjoiTGVvcGFyZCIsImNvbG91ciI6Im9yYW5nZSJ9.LF-​​4HNxgzhqYaIQKTImwO8A4SHIZfVYzG

我什至尝试更改标头 HS256 或 HS384 中的算法,然后在函数内部对更改进行硬编码,没有任何区别

任何建议将不胜感激

【问题讨论】:

试试base64UrlEncoding:function base64url_encode($data) return rtrim( strtr(base64_encode($data), '+/', '-_'), '='); 我试了一下,结果一样,很奇怪 一旦我把它放在调试器中,然后在那里更改算法,然后回到它工作的相同算法,但 JWT 会为它创建自己的新签名 token 看起来基本没问题,只有 alg 标头错误。您是否也将秘密粘贴到 jwt.io 调试器的 verify signature 下的秘密字段中? 现在我认为它有效:),希望它不太好,我打算用不同的号码再试一次。你认为秘密应该用随机数生成吗? 【参考方案1】:

在您的代码中,您使用的是 HMAC 散列,它采用算法参数 sha256sha384。这些算法名称与可在 JWT 中使用的算法名称不同。

在RFC 7517 section 4.1.1 您可以阅读alg 标头:

可以在 IANA 中找到为此用途定义的“alg”值列表 建立“JSON Web 签名和加密算法”注册表 [JWA];此注册表的初始内容是值 [JWA] 第 3.1 节中定义。

根据RFC7518 section 3.1 for HMAC ShaXXX 算法,你有你使用HSXXX,例如HS256HS384

JWT.io 调试器或任何其他尝试验证 JWT 的软件会读取此标头,然后尝试使用算法。如果使用非标准名称,验证软件将找不到正确的算法。

关于JWT.io的使用注意事项:不要忘记将秘密粘贴到调试器右列Verify Signature下的输入字段中,将令牌粘贴到左栏。如果您忘记了密码,则无法验证令牌,如果您将密码粘贴到令牌后,可能会重新计算签名并在左侧更改。

【讨论】:

我确实尝试过并再次尝试,同样的事情发生了。我将发布更新的代码。所以基本上我在标题中使用 HS256,我只是为 HMAC 散列硬编码 sha256 吗?还是有别的办法? 我相信它现在适用于 jps,我想我之前尝试过,但它有效,并且感谢您强调 alg 差异,现在它有效,我基本上是在做一个从 HS 到 SHA 的 str_replace,保存我从硬编码它

以上是关于PHP 中的自定义 JWT 一直说签名无效的主要内容,如果未能解决你的问题,请参考以下文章

springboot 微服务中的自定义 JWT 令牌

JWT 方法中的自定义刷新令牌方法

JWT 身份验证不适用于 Django 中的自定义控制器

.NET 库中的 JWT 无效签名

Zend:如何正确破坏 PHP 7 中的自定义对象?

Prorogate PassportJS 中的自定义错误