Warm tip: This article is reproduced from serverfault.com, please click

typescript-如何在Deno中验证具有RS256签名的JWT?

(typescript - How to verify a JWT with RS256 signature in Deno?)

发布于 2020-06-06 06:42:06

我想验证来自Google JWT的签名,该签名目前使用RS256作为签名算法(来自Google的证书:https : //www.googleapis.com/oauth2/v3/certs),也是我所能找到的唯一一个库for Deno处理HS256(https://deno.land/x/djwt)。

我真的不参与整个密码游戏,也许有人知道我如何验证签名,也许已经有一个例子了?我真的不知道我需要使用SHA-256进行哈希运算还是使用RSA的方式,当我尝试查找如何实现此功能时,我看到了很多技术上的解释,但没有关于如何处理的真正示例。

我通常只在Node上使用过Google的脚本包,请参见:https : //developers.google.com/identity/sign-in/web/backend-auth

我有使用SHA-256进行哈希处理的函数,但关于RSA却一无所知?

Questioner
Eden
Viewed
0
jps 2021-02-03 19:46:36

djwt 1.6版开始,就支持RS256

但是,这里我使用一个名为God Crypto的加密模块来验证RS256签名令牌。God Crypto具有解析JSON Web密钥(JWK)的功能,这是我们需要验证Google提供的JWT的功能。

首先,我将展示一个简短的示例,其中包含JWK的硬编码值和为该演示组成的令牌:

import { RSA, encode } from "https://deno.land/x/god_crypto@v1.4.8/mod.ts";

const jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlctNjduZWt0WVRjOEpWWVBlV0g1c1dlN1JZVm5uMFN5NzQxZjhUT0pfQWMifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hiKxeC66LIyVKOXjiOk7iScFPy_5-ATw7hEfqGij8sBZmwXAeTPT5BRFYHitFKSXomGqmy_63LLvg4zbhcTTmNf8XIeDAuLsC32soO5woSByisswWHVf8BgxMkI_FPW_oEtEQ8Xv3FL_1rF9j9Oy3jIjgjqhFhXUtsSQWAeuGYH-OQljFwiuO5Bqexcw-H71OEWvQLQof_6KJ0viJyte8QEwEVridyO834-ppHzeaoW2sTvZ22ZNfxPCew0Ul2V_TxHTtO7ZuJCZ81EmeIV6dYJ2GrYh3UN1x1PHy4-tEn-PL4otlaO3PYOcXfCHxHa6xtPsquzPZJnB1Vq8zULLfQ"

// public key in JSON Web Key(JWK) format:
const pubJWK = {
    "kty": "RSA",
    "e": "AQAB",
    "use": "sig",
    "kid": "W-67nektYTc8JVYPeWH5sWe7RYVnn0Sy741f8TOJ_Ac",
    "alg": "RS256",
    "n": "kFpGoVmBmmKepvBQiwq3hU9lIAuGsAPda4AVk712d3Z_QoS-5veGp4yltnyEFYyX867GOKDpbH7OF2uIjDg4-FPZwbuhiMscbkZzh25SQmfRtCT5ocUloQiopBcNAE-sd1p-ayUJWjhPrFoBrBLZHYxVEjY4JrWevQDj7kSeX7eJpud_VuZ77TNoIzj7d_iUuJUUlqF1ZF540igHKoVJJ6ujQLHh4ob8_izUuxX2iDq4h0VN3-uer59GsWw6OHgkOt85TsjMwYbeN9iw_7cNfLEYpSiH-sVHBCyKYQw7f8bKaChLxDRhUUTIEUUjGT9Ub_A3gOXq9TIi8BmbzrzVKQ"
}

// parse the JWK to RSA Key
const publicKey = RSA.parseKey(pubJWK)
const rsa = new RSA(publicKey)

// split the token into it's parts for verifcation
const [headerb64, payloadb64, signatureb64] = jwt.split(".")

// verify the signature based on the given public key
console.log(await rsa.verify(
    encode.base64url(signatureb64),
    headerb64 + "." + payloadb64,
    { algorithm: "rsassa-pkcs1-v1_5", hash: "sha256" },
  ))

你可以直接运行上面的代码并获得结果

真的

成功进行验证。

第二个示例从google certs端点加载JWKS(JSON Web密钥集),尝试查找匹配的密钥,然后在找到匹配的密钥时验证令牌。

令牌头包含一个密钥ID(“孩子”),该ID标识应用于验证的密钥。

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "W-67nektYTc8JVYPeWH5sWe7RYVnn0Sy741f8TOJ_Ac"
}
import { RSA, encode } from "https://deno.land/x/god_crypto@v1.4.8/mod.ts";
import { decode } from "https://deno.land/x/djwt@v2.2/mod.ts"

// the JWT that we want to verify
const jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlctNjduZWt0WVRjOEpWWVBlV0g1c1dlN1JZVm5uMFN5NzQxZjhUT0pfQWMifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hiKxeC66LIyVKOXjiOk7iScFPy_5-ATw7hEfqGij8sBZmwXAeTPT5BRFYHitFKSXomGqmy_63LLvg4zbhcTTmNf8XIeDAuLsC32soO5woSByisswWHVf8BgxMkI_FPW_oEtEQ8Xv3FL_1rF9j9Oy3jIjgjqhFhXUtsSQWAeuGYH-OQljFwiuO5Bqexcw-H71OEWvQLQof_6KJ0viJyte8QEwEVridyO834-ppHzeaoW2sTvZ22ZNfxPCew0Ul2V_TxHTtO7ZuJCZ81EmeIV6dYJ2GrYh3UN1x1PHy4-tEn-PL4otlaO3PYOcXfCHxHa6xtPsquzPZJnB1Vq8zULLfQ"

// get the JSON Web Key Set (JWKS) from google certs endpoint
const certs = fetch("https://www.googleapis.com/oauth2/v3/certs");
var jwks = await certs.then((response) => {
  return response.json()
})


// decode the JWT to get the key Id ('kid') from the header
// in Version 2.2 of djwt decode returns a 3 tuple instead of an object
const [ header, payload, signature  ] = decode(jwt)
var keyId = Object(header).kid

// find the matching JSON Web Key (JWK) 
var pubjwk = findJWKByKeyId(String(keyId))

// parse the JWK to RSA Key
if (pubjwk) {
    const publicKey = RSA.parseKey(pubjwk)
    const rsa = new RSA(publicKey)

    // split the token into it's parts for verifcation
    const [headerb64, payloadb64, signatureb64] = jwt.split(".")

    // verify the signature based on the given public key
    console.log(await rsa.verify(
        encode.base64url(signatureb64),
        headerb64 + "." + payloadb64,
        { algorithm: "rsassa-pkcs1-v1_5", hash: "sha256" },
    ))
}
else
{
    console.log("key with kid (" + keyId +") not found")
}

// function to find a certain JWK by its Key Id (kid)
function findJWKByKeyId(kid:string) {
    return jwks.keys.find(
        function(x:string){ return Object(x).kid == kid }
    )
  }

在你看到的令牌头"alg": "RS256",但是rsa.verify()algorithm: "rsassa-pkcs1-v1_5"被使用,这是i将长格式RS的RS256`,斯科特布雷迪解释

由于给定令牌(在jwt.io上创建的示例)未由Google签名,因此找不到匹配的密钥,因此无法对其进行验证。使用你自己的Google签名的JWT测试上述代码。

验证码的某些部分基于God Crypto Github页面上的示例