编辑:我找到了答案。滚动到该问题的底部。
我正在使用NodeJS身份验证服务器,并且希望使用Google签名对JSON Web令牌(JWT)进行签名。
我正在使用Google Cloud密钥管理服务(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');
答案 0 :(得分:2)
您没有在问题中发布代码,所以我不知道您如何构建用于签名的JWT。
[将代码添加到问题后,请在2019年1月18日编辑]
您的代码正在向后签名。您正在创建签名,并尝试将其附加到JWT Headers + Payload。相反,您要使用JWT标头+有效负载并对数据进行签名,然后将签名附加到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。
[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。
步骤2: 取得JWT有效负载并转换为Base-64。我们称它为payload_b64。
步骤3:
将编码的标头和有效负载在点.
+'之间插入点hdr_b64
。 + payload_b64`。我们称它为body_b64。
第4步: 通常,使用专用密钥通过SHA256withRSA(通常称为“ RS256”)对JWS进行签名:
signature = sign(body_b64, RS256, private_key)
现在将签名转换为Base-64。让我们称之为signature_b64。
要创建最终的JWS:
jws = body_b64 +'。 + signature_b64。
建议:
您要使用KMS创建签名JWT吗?我不会推荐这个。 KMS中存储着一个成本访问密钥。带签名的JWT用私钥签名并用公钥验证。您将如何发布公钥?您在访问私钥和公钥时需要什么性能级别(您将多久进行一次签名和验证)?
在Google Cloud Platform中创建服务帐户时,会为您创建一个密钥对。该密钥对具有一个ID,该ID具有Internet上可用的公钥,并且私钥存在于服务帐户Json凭证文件中。我将使用服务帐户来创建Signed-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