5

编辑:我找到了答案。滚动到这个问题的底部。

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

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

这是我获取签名的代码:

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

signature = signatureObject["0"].signature

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

在此处输入图像描述

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

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

JWT 应该如下所示:

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() 方法:

signatureString = signature.toString('base64');

然后我可以通过使用获得原始签名八位字节流

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

1 回答 1

2

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

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

您的代码正在反向执行签名。您正在创建一个签名并尝试将其附加到 JWT Headers + Payload。您想要取而代之的是 JWT Headers + Payload 并签署该数据,然后将签名附加到 JWT 以创建 Signed-JWT。

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

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

signature = sign(body_b64, name);

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

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

[结束编辑]

示例数据:

智威汤逊标题:

{
    alg: RS256
    kid: 0123456789abcdef62afcbbf01234567890abcdef
    typ: 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。

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

第 3 步:将编码后的标头和有效负载与中间的点.连接起来:hdr_b64+ '.' +有效载荷_b64`。我们称之为body_b64。

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

signature = sign(body_b64, RS256, private_key)

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

要创建最终的 JWS:

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

建议:

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

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

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

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
于 2019-01-18T09:39:01.077 回答