在创建 JWT 令牌期间了解 RS256 和 SHA256

Understanding RS256 and SHA256 during JWT Token creation

我正在 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;

我可以清楚地看到的一个区别是,对于 php 端的 signature generation function,我将 sha256 作为算法传递,而在 JavaScript RS256通过了。

我了解到 sha256 只是一种哈希算法,而 RS256 用于编码,但在我在 php 中找到的所有库中,它们仅在 [=] 中内部传递 sha256 18=] 函数。并且openssl_sign没有RS256作为算法参数。

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

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

PS :我正在 php.

中寻找解决方案
  • KJUR.jws.JWS.sign consists of three portions separated by a dot. The first part is the Base64url-encoded JSON-string sHeader, the second part is the Base64url-encoded JSON-string sPayload and the third part is the Base64url-encoded signature. The data to be signed consist of the first two portions including the dot separating the two portions. RS256 means that SHA256 and RSA with RSASSA-PKCS1-v1_5 padding is used for the signature. This can also be easily verified online, e.g. here 的 return 值,由此选择 SHA256withRSA 作为算法。

  • 假定相同的密钥和应用相同的待签名数据。

  • jsrsasign 使用 Base64 url-encoding (RFC4648, sect. 5), while PHP (or more precisely the base64_encode-method) uses standard Base64-encoding (RFC4648, sect. 4), which most likely is one cause of the issue. This means that the encoding in the current PHP-code must be changed to Base64url, e.g. here.

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