作者在 2021-04-30 14:52:02 发布以下内容
踩坑 PHP验签JWT RS256
使用openssl_verify验签时总是报错
error:04091077:rsa routines:int_rsa_verify:wrong sart line
或者
error:04091077:rsa routines:int_rsa_verify:wrong signature length
对比一圈类库,发现需要满足如下几个条件:
1. 公钥必须按64位换行
$pubkey = file_get_contents("./pubkey");
$search = [
"-----BEGIN PUBLIC KEY-----",
"-----END PUBLIC KEY-----",
"\n",
"\r",
"\r\n"
];
$public_key=str_replace($search,"",$pubkey);
$public_key=$search[0] . PHP_EOL . chunk_split($public_key, 64,"\n") . $search[1];
2. 签名base64_decode前必须将Byte数使用=号补齐4的倍数
function urlsafeB64Decode($sign)
{
$remainder = \strlen($sign) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= \str_repeat('=', $padlen);
}
return \base64_decode(\strtr($sign, '-_', '+/'));
}
3. 验签的数据不是整个jwt串,而是header+"."+payload,并不包含sign
$result = openssl_verify("$tokenarr[0].$tokenarr[1]", urlsafeB64Decode($sign), $res, OPENSSL_ALGO_SHA256);
注:“encoding/base64” 提供了四种编码和解码的方法:
- StdEncoding , 常规编码,bit不足 3 倍时,使用 0 补齐。Byte不足4倍时,使用=补齐
- URLEncoding , URL safe 编码,替换掉字符串中的特殊字符 +/ 转化成 -_
- RawStdEncoding , 常规编码,末尾不补 =
- RawURLEncoding , URL safe 编码,末尾不补 =
附整体示例:
<?php
$token = "RS256 jwt串";
$tokenarr = explode(".",$token);
$sign = $tokenarr[2];
$pubkey = file_get_contents("./pubkey");
$search = [
"-----BEGIN PUBLIC KEY-----",
"-----END PUBLIC KEY-----",
"\n",
"\r",
"\r\n"
];
$public_key=str_replace($search,"",$pubkey);
$public_key=$search[0] . PHP_EOL . chunk_split($public_key, 64,"\n") . $search[1];
$res = openssl_get_publickey($public_key);
if($res){
$result = openssl_verify("$tokenarr[0].$tokenarr[1]", urlsafeB64Decode($sign), $res, OPENSSL_ALGO_SHA256);
openssl_free_key($res);
if(!$result){
var_dump(openssl_error_string());die();
}
var_dump($result);
}
function urlsafeB64Decode($input)
{
$remainder = \strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= \str_repeat('=', $padlen);
}
return \base64_decode(\strtr($input, '-_', '+/'));
}