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

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

问题描述

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

我正在使用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密钥管理服务(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标头+有效负载并对数据进行签名,然后将签名附加到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.

[END EDIT]

[END EDIT]

示例数据:

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有效负载并转换为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步: 通常,使用专用密钥通过SHA256withRSA(通常称为"RS256")对JWS进行签名:

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 +'. + signature_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,该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 Key Management Service签名JSON Web令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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