使用 Google Cloud Key Management Service 签署 JSON Web Tokens [英] Using Google Cloud Key Management Service to sign JSON Web Tokens

查看:14
本文介绍了使用 Google Cloud Key Management Service 签署 JSON Web Tokens的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找到了答案.滚动到该问题的底部.

我正在使用 NodeJS 身份验证服务器,我想使用 google 签名签署 JSON Web 令牌 (JWT).

I am working on a NodeJS authentication server and I would like to sign JSON Web Tokens (JWT) using google signatures.

我正在使用 Google Cloud Key Management Service (KMS),并创建了一个密钥环和一个非对称签名密钥.

I am using Google Cloud Key Management Service (KMS) and I created a key ring and an asymmetric signing key.

这是我获取签名的代码:

This is my code to get the signature:

signatureObject = await client.asymmetricSign({ name, digest })

signature = signatureObject["0"].signature

我的 Google 签名对象如下所示:

My Google signature object looks like this:

我的问题:如何使用 Google 签名签署 JWT?

或者换句话说,如何将 Google 签名连接到 JWT 的 (header.payload)?

Or in other words, how do I concatenate the Google signature to the (header.payload) of the JWT?

JWT 应该如下所示:

The JWT should look something like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. (GoogleSignature)

我正在使用的代码:

签名:

async function sign(message, name) {
  hashedMessage = crypto.createHash('sha256').update(message).digest('base64');
  digest = { 'sha256': hashedMessage }

  signatureObject = await client.asymmetricSign({ name, digest }).catch((err) => console.log(err))
  signature = signatureObject["0"].signature
  signJWT(signature)
}

创建 JWT:

function signJWT(signature) {
  header = {
    alg: "RS256",
    typ: "JWT"
  }

  payload = {
    sub: "1234567890",
    name: "John Doe",
    iat: 1516239022
  }

  JWT = base64url(JSON.stringify(header)) + "." +
        base64url(JSON.stringify(payload)) + "." + 
        ???signature??? ; // what goes here?
}

验证:

async function validateSignature(message, signature) {
  // Get public key
  publicKeyObject = await client.getPublicKey({ name }).catch((err) => console.log(err))
  publicKey = publicKeyObject["0"].pem

  //Verify signature
  var verifier = crypto.createVerify('sha256');
  verifier.update(message)
  var ver = verifier.verify(publicKey, signature, 'base64')

  // Returns either true for a valid signature, or false for not valid.
  return ver
}

<小时>

答案:

我可以像这样使用 toString() 方法:

I can use the toString() method like so:

signatureString = signature.toString('base64');

然后我可以使用

var buffer = Buffer.from(theString, 'base64');

推荐答案

你没有在你的问题中发布你的代码,所以我不知道你是如何构建用于签名的 JWT.

You did not post your code in your question, so I do not know how you are building the JWT for signing.

[将代码添加到问题后于 2019 年 1 月 18 日编辑]

您的代码正在反向执行签名.您正在创建一个签名并尝试将其附加到 JWT Headers + Payload.您希望改为使用 JWT Headers + Payload 并签署该数据,然后将签名附加到 JWT 以创建 Signed-JWT.

Your code is doing the signature backwards. You are creating a signature and trying to attach it to the JWT Headers + Payload. You want to instead take the JWT Headers + Payload and sign that data and then attach the signature to the JWT to create a Signed-JWT.

使用您的源代码的伪代码:

Psuedo code using your source code:

body_b64 = base64url(JSON.stringify(header)) + "." + base64url(JSON.stringify(payload))

signature = sign(body_b64, name);

jwt = body_b64 + '.' + base64url(signature)

注意:我不确定 signatureObject["0"].signature 返回的签名是什么数据格式.在转换为 base64 之前,您可能必须先转换它.

Note: I am not sure what data format the signature is returned by signatureObject["0"].signature. You may have to convert this before converting to base64.

[结束编辑]

示例数据:

JWT 标头:

{
    alg: RS256
    kid: 0123456789abcdef62afcbbf01234567890abcdef
    typ: JWT
}

JWT 负载:

{
  "azp": "123456789012-gooddogsgotoheaven.apps.googleusercontent.com",
  "aud": "123456789012-gooddogsgotoheaven.apps.googleusercontent.com",
  "sub": "123456789012345678901",
  "scope": "https://www.googleapis.com/auth/cloud-platform",
  "exp": "1547806224",
  "expires_in": "3596",
  "email": "someone@example.com.com",
  "email_verified": "true",
  "access_type": "offline"
}

算法:

SHA256withRSA

创建签名 JWT (JWS):

第 1 步:获取 JWT 标头并转换为 Base-64.我们称之为 hdr_b64.

Step 1: Take the JWT Header and convert to Base-64. Let's call this hdr_b64.

第 2 步:获取 JWT Payload 并转换为 Base-64.我们称之为payload_b64.

Step 2: Take the JWT Payload and convert to Base-64. Let's call this payload_b64.

第 3 步:用一个点 . 连接编码的标头和有效负载:hdr_b64 + '.'+有效载荷_b64`.我们称之为 body_b64.

Step 3: Concatenate the encoded header and payload with a dot . in between: hdr_b64 + '.' + payload_b64`. Let's call this body_b64.

第 4 步:通常,JWS 使用 SHA256withRSA 进行签名,通常称为RS256",使用私钥:

Step 4: Normally a JWS is signed with SHA256withRSA often called "RS256" using the Private Key:

signature = sign(body_b64, RS256, private_key)

现在将签名转换为 Base-64.让我们称之为 signature_b64.

Now convert the signature to Base-64. Let call this signature_b64.

创建最终的 JWS:

jws = body_b64 + '.'+ 签名_b64.

jws = body_b64 + '.' + signature_b64.

建议:

您想使用 KMS 创建签名 JWT 吗?我不会推荐这个.访问存储在 KMS 中的密钥是有成本的.签名 JWT 使用私钥签名并使用公钥进行验证.你将如何发布公钥?您在访问私钥和公钥时需要什么性能级别(您多久进行一次签名和验证)?

Do you want to use KMS to create Signed JWTs? I would not recommend this. There is a cost accessing keys stored in KMS. Signed-JWTs are signed with the private key and verified with the public key. How are you going to publish the public key? What performance level do you need in accessing the private and public keys (how often will you be signing and verifying)?

当您在 Google Cloud Platform 中创建服务帐号时,系统会为您创建一个密钥对.此密钥对的 ID 包含 Internet 上可用的公钥,并且私钥存在于服务帐户 Json 凭据文件中.我会使用服务帐户来创建签名 JWT,而不是 KMS 中的密钥对.

When you create a service account in Google Cloud Platform, a keypair is created for you. This keypair has an ID with the public key available on the Internet and the private key is present in the Service Account Json credentials file. I would use a Service Account to create Signed-JWTs instead of a keypair in KMS.

在 Python 中创建和签名的示例代码:

Example code in Python to create and sign:

def create_signed_jwt(pkey, pkey_id, email, scope):
    '''
    Create a Signed JWT from a service account Json credentials file
    This Signed JWT will later be exchanged for an Access Token
   '''

    import jwt

    # Google Endpoint for creating OAuth 2.0 Access Tokens from Signed-JWT
    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    issued = int(time.time())
    expires = issued + expires_in   # expires_in is in seconds

    # Note: this token expires and cannot be refreshed. The token must be recreated

    # JWT Headers
    headers = {
        "kid": pkey_id, # This is the service account private key ID
        "alg": "RS256",
        "typ": "JWT"    # Google uses SHA256withRSA
    }

    # JWT Payload
    payload = {
            "iss": email,           # Issuer claim
            "sub": email,           # Issuer claim
            "aud": auth_url,        # Audience claim
            "iat": issued,          # Issued At claim
            "exp": expires,         # Expire time
            "scope": scope          # Permissions
    }

    # Encode the headers and payload and sign creating a Signed JWT (JWS)
    sig = jwt.encode(payload, pkey, algorithm="RS256", headers=headers)

    return sig

这篇关于使用 Google Cloud Key Management Service 签署 JSON Web Tokens的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆