使用 Google Cloud 密钥管理服务签署 JSON Web 令牌 [英] Using Google Cloud Key Management Service to sign JSON Web Tokens

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

问题描述

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

我在 NodeJS 身份验证服务器上工作,我想使用谷歌签名签署 JSON 网络令牌 (JWT).

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

我正在使用 Google Cloud 密钥管理服务 (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.

[在将代码添加到问题后编辑 1/18/2019]

您的代码正在反向执行签名.您正在创建签名并尝试将其附加到 JWT 标头 + 有效负载.您想要改为使用 JWT 标头 + 有效负载并对该数据进行签名,然后将签名附加到 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 + '.'+ payload_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:

To create the final 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 凭据文件中.我将使用服务帐户来创建 Signed-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 密钥管理服务签署 JSON Web 令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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