无法使用 google kms 生成有效的 jwt 签名

Posted

技术标签:

【中文标题】无法使用 google kms 生成有效的 jwt 签名【英文标题】:Can't generate valid jwt signature with google kms 【发布时间】:2020-03-13 02:11:40 【问题描述】:

我正在使用带有非对称签名密钥的 Google KMS (https://cloud.google.com/kms/) 在 node.js 应用程序中签署 JSON Web 令牌 (jwt)。

我能够创建标头和有效负载,并且使用 Google KMS nodejs 库 (https://github.com/googleapis/nodejs-kms) 我可以签署令牌。

但是生成的token好像是无效的。

其实我正在做以下步骤来生成一个令牌:

    将 jwt-header 定义为对象 jwt-header 对象转字符串 base64url 编码 jwt-header-string 将 jwt-payload 定义为对象 jwt-payload 对象到字符串 base64url 编码 jwt-payload-string 连接(header.payload) 将字符串解码为base64字节数组 在字节数组上创建 sha256 散列 从 google kms 中选择非对称密钥 使用非对称密钥获取签名字节数组 在签名上使用 base64url 编码 构建令牌(header.payload.signature)

此令牌总是带来错误(无效签名)。见https://jwt.io/

验证令牌的公钥:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmv3Slq7ofruWhFRXmnvt
/4WQuoJtoF2UQMtXmsZAZSODalklN21lV9t1ECAXOyOQX7E2QF8RZfJow5ImeTM5
WWHDhvFcg1/rI6bPIkkp4+Lu4Ljo8IIfYkEbIHt8+yOumEqiA1cvBR1TbojHMl4C
XW8jS4y4g7U6ZNYqKxOh9yvX6yUE0WRSzffRNVvx+Z5SNpmyjOXH/8A8e9BpG8tl
tAwdbtLd7Z+hcr60IERSWgqxnzUwzFWqdo4VNgLG68b1lKocbL8f0SnZiG0huyh0
tUEntR7PFWDePc2fOJmY9N9phgoD5FQjUQQiNipZi/Jw/z/BUz+utmQHwHNqyvCQ
ZQIDAQAB
-----END PUBLIC KEY-----

构建 jwt 的代码:

const kms = require('@google-cloud/kms');
const crypto = require('crypto');
const base64url = require('base64url');

async function main() 
    const client = new kms.KeyManagementServiceClient(
        keyFilename: "./googleCloudKey.json"
    );

    const projectId = '...';
    const locationId = 'europe';
    const keyRingId = '...';
    const cryptoKeyId = '...';
    const cryptoKeyVersion = '1';

    const header = base64url(JSON.stringify(
        "alg": "RS256",
        "typ": "JWT",
        "issuer": "login.myapp.com",
        "audience": "*.myapp.com"
    ));
    const payload = base64url(JSON.stringify(
        "userId": "1234567890",
        "userName": "John Doe"
    ));

    const digest = crypto.createHash("sha256").update(Buffer.from(`$header.$payload`, "base64")).digest("base64");
    const name = client.cryptoKeyVersionPath(
        projectId,
        locationId,
        keyRingId,
        cryptoKeyId,
        cryptoKeyVersion
    );

    try 
        const result = await client.asymmetricSign(
            name: name, 
            digest: 
                sha256: digest
            
        );

        const signature = base64url.fromBase64(result[0].signature.toString("base64"));

        console.log("====== HEADER =====");
        console.log(header);
        console.log();
        console.log("====== PAYLOAD =====");
        console.log(payload);
        console.log();
        console.log("====== SIGNATURE =====");
        console.log(signature);
        console.log();
        console.log();
        console.log("===== JWT =====");
        console.log(`$header.$payload.$signature`);
     catch(e) 
        console.error(e);
    



main().catch(console.error);

生成的令牌如下所示(= 最后一个 console.log 的输出):

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImlzc3VlciI6ImxvZ2luLm15YXBwLmNvbSIsImF1ZGllbmNlIjoiKi5teWFwcC5jb20ifQ.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwidXNlck5hbWUiOiJKb2huIERvZSJ9.WVdM2NT5IGYKuCMV393yD7grA4GyVIrorL2OF-MHcRZESwPC3bOZIsx254IkMDInFyui74N6qEpHIe6UpR1JeuojMaGEANvSE0TtFpYgykU7xORmVEsjuZSYyKeEaTPAMwmXVPEKi5gQA9qlfQjTXE-h1xWYt2N3-pj2IHcgpgC-tarN1_TLNxZ5it2TrfpfGztI13L5WHYEFidExde9sxasvJsHZR3ax0wnoPn9V9rfqdXrEtG6-cdi9PAQprQClVOETtvpZNcCZpIlciHsaYBla5JjowbUmecSjQ54F-CuOggxvGvy16uG9p93ETlUyAknPTCGaMf9URyKkssYaw

【问题讨论】:

Using Google Cloud Key Management Service to sign JSON Web Tokens的可能重复 【参考方案1】:

在这个sn-p中:

Buffer.from(`$header.$payload`, "base64")

您正在对标头和有效负载的串联进行 base64 解码。但是 JWS 规范并没有要求这样做。 https://www.rfc-editor.org/rfc/rfc7515#section-5.1

【讨论】:

以上是关于无法使用 google kms 生成有效的 jwt 签名的主要内容,如果未能解决你的问题,请参考以下文章

Auth0 java-jwt 库无法验证有效令牌

我应该如何使用 Google Cloud KMS 存储由另一个应用程序生成的访问令牌?

使用 RS256 生成的 JWT 可以被 jwt.io 网站解码吗?

Google Cloud KMS 错误 - 您所在地区无法访问此 API。 (HTTP 状态 - 403)

生成 JWT 表单头和有效负载

如何使用 JWT for Google firebase 生成身份验证令牌?