我想验证来自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却一无所知?
但是,这里我使用一个名为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页面上的示例
有趣的事实:God crypto的作者和我对此事写得不和谐,我问了他之后,他实施了解决方案,忘了在此处更新问题,但是是的,我同意god_crypto现在是有效的解决方案:)
感谢您的回应。一步一步神加密货币和djwt都在变得更好。我认为,通过对这些库进行进一步的开发,可以在将来简化上面的代码。