首页 > 解决方案 > 在 JWT Token 创建过程中了解 RS256 和 SHA256

问题描述

我正在使用 PHP 中的私钥创建 JWT 令牌。为此,我正在使用 OpenSSL 库。在任何事情之前,我将分享我的代码:

PHP

    $header = [
        self::ALG => self::RS256,
        self::TYP => self::JWT
    ];
    $payload = [
        "iss" => $this->getClientID(),
        "iat" => time(),
        "exp" => time()+999
    ];
    $header = base64_encode(json_encode($header));
    $payload = base64_encode(json_encode($payload));
    $token = $header.".".$payload;
    $pkey = openssl_pkey_get_private($this->getPrivateKey(), $this->getPassPhrase());
    openssl_sign($token, $signature, $pkey, 'sha256'); //no algorithm specifically for rs256
    $sign = base64_encode($signature);
    return $token.".".$sign;

因此,此 JWT 令牌将用于在我尝试访问的服务器中进行身份验证。但是我从外部服务器得到响应,因为Bad Request我的 JWT 令牌创建中发生了问题。

使用相同的凭据,我尝试使用库在 javascript 中jsrsasign,然后它给了我正确的响应。

JAVASCRIPT

// Header
var oHeader = { alg: 'RS256', typ: 'JWT' };
// Payload
var oPayload = {};
var tNow = rs.KJUR.jws.IntDate.get('now');
var tEnd = tNow + 1000;
oPayload.iss = "playground.pizza";
oPayload.iat = tNow;
oPayload.exp = tEnd;
var sHeader = JSON.stringify(oHeader);
var sPayload = JSON.stringify(oPayload);
var pkey = "my private key" //I replaced all the new line with \n here and had in one line
var prvKey = rs.KEYUTIL.getKey(pkey, "my_pass_phrase");
var sJWT = rs.KJUR.jws.JWS.sign("RS256", sHeader, sPayload, prvKey);
ultraSecureToken = sJWT;

我可以清楚地看到的一个区别是,对于signature generation functionphp 端,我sha256作为算法传递,而在 JavaScriptRS256中传递。

我读到 sha256 只是一种散列算法,而 RS256 用于编码,但在我在 php 中找到的所有库中,它们sha256仅在内部传递openssl_sign函数。并且openssl_sign没有 RS256 作为算法参数。

所以,首先我哪里出错了。

其次,有没有一种方法可以在 php.ini 中使用 RS256 生成签名。

PS:我正在寻找 php 中的解决方案。

标签: phpjwtrsasha

解决方案


  • 的返回值KJUR.jws.JWS.sign由以点分隔的三部分组成。第一部分是 Base64url 编码的 JSON 字符串sHeader,第二部分是 Base64url 编码的 JSON 字符串sPayload,第三部分是 Base64url 编码的签名。要签名的数据由前两部分组成,包括分隔两部分的点。RS256表示使用带有 RSASSA-PKCS1-v1_5 填充的 SHA256 和 RSA 进行签名。这也可以很容易地在线验证,例如在这里,将SHA256withRSA被选为算法。

  • openssl_sign还使用带有 RSASSA-PKCS1-v1_5 填充的 RSA,因此使用 SHA256 创建相同的签名,假设应用了相同的密钥和相同的要签名的数据。

  • jsrsasign使用Base64 url​​ 编码(RFC4648,第 5 节),而 PHP(或更准确地说是base64_encode- 方法)使用标准Base64 编码(RFC4648,第 4 节),这很可能是问题的原因之一。这意味着当前 PHP 代码中的编码必须更改为 Base64url,例如此处

  • 当然,PHP 代码中的底层 JSON 字符串($header$payload$token也必须与 JavaScript 代码中的对应部分相同,否则签名会有所不同。由于 PHP 代码不完整,因此无法检查这可能是问题的另一个原因。


推荐阅读