oauth2.0 来自Google的RSA 256公钥证书失败了一个密钥

kcwpcxri  于 5个月前  发布在  Go
关注(0)|答案(2)|浏览(68)

为了验证一个google oauth2令牌,我将根据以下公式中的模数(n)和指数(e)为kid“b863b534069bfc0207197bcf831320d1cdc2cee2”生成一个公钥:

{
"alg": "RS256",
"n": "8h6tCwOYDPtzyFivNaIguQVc_yBO5eOA2kUu_MAN8s4VWn8tIfCbVvcAz3yNwQuGpkdNg8gTk9QmReXl4SE8m7aCa0iRcBBWLyPUt6TM1RkYE51rOGYhjWxo9V8ogMXSBclE6x0t8qFY00l5O34gjYzXtyvyBX7Sw5mGuNLVAzq2nsCTnIsHrIaBy70IKU3FLsJ_PRYyViXP1nfo9872q3mtn7bJ7_hqss0vDgUiNAqPztVIsrZinFbaTgXjLhBlUjFWgJx_g4p76CJkjQ3-puZRU5A0D04KvqQ_0AWcN1Q8pvwQ9V4uGHm6Bop9nUhIcZJYjjlTM9Pkx_JnVOfekw",
"use": "sig",
"kid": "b863b534069bfc0207197bcf831320d1cdc2cee2",
"e": "AQAB",
"kty": "RSA"
}

字符串
然后在php中创建RSA 256公钥:

$rsa = new Crypt_RSA();
    $modulus = new Math_BigInteger(base64url_decode($cert["n"]), 256);
    $exponent = new Math_BigInteger(base64url_decode($cert["e"]), 256);
    $rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
    $rsa->setPublicKey();
    $public_key = $rsa->getPublicKey();


这将生成公钥:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuopEuQyOKMsQq90I/5on
1nNBPc7stMvsN1HC+Pgyu8nJ1qWwaAAqIv4edo2oG/Bo3eg6p+OjG3nbFL62S6hE
aJLUVfxhW5GQuxQlsvaA2MsZuZCRyKTv8bm641wM+biGVZLiDsLRylVdpxf4aGa9
9zZw+QZMVKL4f9B4SunyTugTaCIu8LBOQesCQp/QJaUjqMDhfEvoFQXiCn6zo3rW
EWBiKxiFBizH9jSfWimJecFhn0Vlv/Vs7pRb0X2y66VS3gTvR6/A3ooNz3tYAJPM
GoE8fAiEghYXXHjmWmgdRx9Qt9sa/ACwv7yx0Th27fw+rrsMSrUyaqRpn/fjIMTu
sQIDAQAB
-----END PUBLIC KEY-----


同样的方法也适用于谷歌的其他几十个RS256 kid,但公钥不适用于这个特定的kid。
我正在验证签名:

openssl_verify($payload_to_verify, $safe_signature, $public_key, OPENSSL_ALGO_SHA256);


响应为“0”表示失败。
编辑#2:找到谷歌版本的公钥:
https://www.googleapis.com/oauth2/v1/certs

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8h6tCwOYDPtzyFivNaIg
uQVc/yBO5eOA2kUu/MAN8s4VWn8tIfCbVvcAz3yNwQuGpkdNg8gTk9QmReXl4SE8
m7aCa0iRcBBWLyPUt6TM1RkYE51rOGYhjWxo9V8ogMXSBclE6x0t8qFY00l5O34g
jYzXtyvyBX7Sw5mGuNLVAzq2nsCTnIsHrIaBy70IKU3FLsJ/PRYyViXP1nfo9872
q3mtn7bJ7/hqss0vDgUiNAqPztVIsrZinFbaTgXjLhBlUjFWgJx/g4p76CJkjQ3+
puZRU5A0D04KvqQ/0AWcN1Q8pvwQ9V4uGHm6Bop9nUhIcZJYjjlTM9Pkx/JnVOfe
kwIDAQAB
-----END PUBLIC KEY-----


我生成的公钥不一样,为什么我生成的公钥是错的?

esyap4oy

esyap4oy1#

我确认RSA Crypt软件包未正确转换密钥。

  • 错钥匙
  • 好钥匙

我尝试用另一个应用程序(web-token/jwt-app)转换该密钥,得到的结果与Google提供的结果相同。

curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar
curl -OL https://github.com/web-token/jwt-app/raw/gh-pages/jose.phar.pubkey

chmod +x jose.phar
./jose.phar key:convert:pkcs1 '{"alg": "RS256","n": "8h6tCwOYDPtzyFivNaIguQVc_yBO5eOA2kUu_MAN8s4VWn8tIfCbVvcAz3yNwQuGpkdNg8gTk9QmReXl4SE8m7aCa0iRcBBWLyPUt6TM1RkYE51rOGYhjWxo9V8ogMXSBclE6x0t8qFY00l5O34gjYzXtyvyBX7Sw5mGuNLVAzq2nsCTnIsHrIaBy70IKU3FLsJ_PRYyViXP1nfo9872q3mtn7bJ7_hqss0vDgUiNAqPztVIsrZinFbaTgXjLhBlUjFWgJx_g4p76CJkjQ3-puZRU5A0D04KvqQ_0AWcN1Q8pvwQ9V4uGHm6Bop9nUhIcZJYjjlTM9Pkx_JnVOfekw","use": "sig","kid": "b863b534069bfc0207197bcf831320d1cdc2cee2","e": "AQAB","kty": "RSA"}'

字符串
最好是警告phpseclib/phpseclib这个问题。

sulc1iza

sulc1iza2#

我写了一个简单的validate_id_token函数:

function validate_id_token($id_token, $target_kid, $target_client_id, $pubkey_pem)
{
    // Create array from token separated by dot (.)
    $token_arr = explode('.', $id_token);
    $headers_enc = $token_arr[0];
    $claims_enc = $token_arr[1];
    $sig_enc = $token_arr[2];

    // Base 64 url decoding
    $headers_arr = json_decode(base64_url_decode($headers_enc), TRUE);
    $claims_arr = json_decode(base64_url_decode($claims_enc), TRUE);
    if (time() > $claims_arr['exp'])
    {
        // The token expired
        return false;
    }

    $sig = base64_url_decode($sig_enc);

    // Validate the kid
    // This will validate that the token was generated by the login provider (such as google, microsoft)
    if ($headers_arr['kid'] != $target_kid) {
        return false;
    }

    // Validate the client id
    // This will validate that the token is related to your developer account and managed by you
    if ($claims_arr['aud'] != $target_client_id)
    {
        return false;
    }

    // Validate the signature
    $token_valid = openssl_verify($headers_enc . '.' . $claims_enc, $sig, $pubkey_pem, OPENSSL_ALGO_SHA256);
    return $token_valid == 1;
}

function base64_url_decode($arg)
{
    $res = $arg;
    $res = str_replace('-', '+', $res);
    $res = str_replace('_', '/', $res);
    switch (strlen($res) % 4) {
        case 0:
            break;
        case 2:
            $res .= "==";
            break;
        case 3:
            $res .= "=";
            break;
        default:
            break;
    }
    $res = base64_decode($res);
    return $res;
}

字符串
该函数验证由

参数:

$id_token -登录提供程序返回的令牌(/#id_token=eyJ....
$target_client_id -令牌生成器的客户端ID(您可以在开发人员帐户的令牌管理中获取)
$target_kid:
1.通过登录提供程序进行登录,以获取一些临时ID令牌(它将在/#id_token=eyJ....上返回)
1.复制id令牌并在https://jwt.io/上输入
1.您的子值位于解码的HEADER x1c 0d1x下
$pubkey_pem
1.如果您使用的是Microsoft登录提供程序,请转到:https://login.microsoftonline.com/common/discovery/v2.0/keys如果您使用的是Google登录提供程序,请转到:https://www.googleapis.com/oauth2/v3/certs
1.在你访问的URL上,搜索kid值。在我的例子中,

1.复制带有kid值的Json对象(在keys下,您只需要复制带有匹配的kid值的json项,并将Json对象粘贴到https://keytool.online/


1.选择PEM PKS#8选项卡

你有$pubkey_pem的值(-----BEGIN PUBLIC KEY-----的东西)你需要将整个生成的文本复制到$pubkey_pem
现在你已经有了函数的所有参数。获取$pubkey_pem$target_kid$target_client_id的过程是每个登录提供程序的一次过程。

相关问题