无法使用 google 公里生成有效的 jwt 签名
Can't generate valid jwt signature with google kms
我正在使用 Google KMS (https://cloud.google.com/kms/) 和非对称签名密钥在 node.js 应用程序中签署 JSON Web 令牌 (jwt)。
我能够创建 header 和有效负载,并且使用 Google KMS nodejs 库 (https://github.com/googleapis/nodejs-kms) 我可以签署令牌。
但生成的令牌似乎无效。
实际上我正在执行以下步骤来生成令牌:
- 定义 jwt-header 为 object
- jwt-header object 到字符串
- base64url 编码 jwt-header-字符串
- 定义 jwt-payload 为 object
- jwt-payload object 到字符串
- base64url 编码 jwt-payload-字符串
- 连接 (header.payload)
- 将字符串解码为 base64 字节数组
- 在字节数组上创建 sha256 哈希
- select 来自 google 公里的非对称密钥
- 使用非对称密钥获取签名字节数组
- 对签名使用base64url编码
- 构建令牌(header.payload.签名)
此令牌总是带来错误(无效签名)。参见 https://jwt.io/
验证令牌的public密钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmv3Slq7ofruWhFRXmnvt
/4WQuoJtoF2UQMtXmsZAZSODalklN21lV9t1ECAXOyOQX7E2QF8RZfJow5ImeTM5
WWHDhvFcg1/rI6bPIkkp4+Lu4Ljo8IIfYkEbIHt8+yOumEqiA1cvBR1TbojHMl4C
XW8jS4y4g7U6ZNYqKxOh9yvX6yUE0WRSzffRNVvx+Z5SNpmyjOXH/8A8e9BpG8tl
tAwdbtLd7Z+hcr60IERSWgqxnzUwzFWqdo4VNgLG68b1lKocbL8f0SnZiG0huyh0
tUEntR7PFWDePc2fOJmY9N9phgoD5FQjUQQiNipZi/Jw/z/BUz+utmQHwHNqyvCQ
ZQIDAQAB
-----END PUBLIC KEY-----
构建jwt的代码:
const kms = require('@google-cloud/kms');
const crypto = require('crypto');
const base64url = require('base64url');
async function main() {
const client = new kms.KeyManagementServiceClient({
keyFilename: "./googleCloudKey.json"
});
const projectId = '...';
const locationId = 'europe';
const keyRingId = '...';
const cryptoKeyId = '...';
const cryptoKeyVersion = '1';
const header = base64url(JSON.stringify({
"alg": "RS256",
"typ": "JWT",
"issuer": "login.myapp.com",
"audience": "*.myapp.com"
}));
const payload = base64url(JSON.stringify({
"userId": "1234567890",
"userName": "John Doe"
}));
const digest = crypto.createHash("sha256").update(Buffer.from(`${header}.${payload}`, "base64")).digest("base64");
const name = client.cryptoKeyVersionPath(
projectId,
locationId,
keyRingId,
cryptoKeyId,
cryptoKeyVersion
);
try {
const result = await client.asymmetricSign({
name: name,
digest: {
sha256: digest
}
});
const signature = base64url.fromBase64(result[0].signature.toString("base64"));
console.log("====== HEADER =====");
console.log(header);
console.log();
console.log("====== PAYLOAD =====");
console.log(payload);
console.log();
console.log("====== SIGNATURE =====");
console.log(signature);
console.log();
console.log();
console.log("===== JWT =====");
console.log(`${header}.${payload}.${signature}`);
} catch(e) {
console.error(e);
}
}
main().catch(console.error);
生成的令牌如下所示(= 最后一个 console.log
的输出):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImlzc3VlciI6ImxvZ2luLm15YXBwLmNvbSIsImF1ZGllbmNlIjoiKi5teWFwcC5jb20ifQ.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwidXNlck5hbWUiOiJKb2huIERvZSJ9.WVdM2NT5IGYKuCMV393yD7grA4GyVIrorL2OF-MHcRZESwPC3bOZIsx254IkMDInFyui74N6qEpHIe6UpR1JeuojMaGEANvSE0TtFpYgykU7xORmVEsjuZSYyKeEaTPAMwmXVPEKi5gQA9qlfQjTXE-h1xWYt2N3-pj2IHcgpgC-tarN1_TLNxZ5it2TrfpfGztI13L5WHYEFidExde9sxasvJsHZR3ax0wnoPn9V9rfqdXrEtG6-cdi9PAQprQClVOETtvpZNcCZpIlciHsaYBla5JjowbUmecSjQ54F-CuOggxvGvy16uG9p93ETlUyAknPTCGaMf9URyKkssYaw
在此代码段中:
Buffer.from(`${header}.${payload}`, "base64")
您正在对 header 和负载的串联进行 base64 解码。但 JWS 规范并不要求这样做。 https://www.rfc-editor.org/rfc/rfc7515#section-5.1
我正在使用 Google KMS (https://cloud.google.com/kms/) 和非对称签名密钥在 node.js 应用程序中签署 JSON Web 令牌 (jwt)。
我能够创建 header 和有效负载,并且使用 Google KMS nodejs 库 (https://github.com/googleapis/nodejs-kms) 我可以签署令牌。
但生成的令牌似乎无效。
实际上我正在执行以下步骤来生成令牌:
- 定义 jwt-header 为 object
- jwt-header object 到字符串
- base64url 编码 jwt-header-字符串
- 定义 jwt-payload 为 object
- jwt-payload object 到字符串
- base64url 编码 jwt-payload-字符串
- 连接 (header.payload)
- 将字符串解码为 base64 字节数组
- 在字节数组上创建 sha256 哈希
- select 来自 google 公里的非对称密钥
- 使用非对称密钥获取签名字节数组
- 对签名使用base64url编码
- 构建令牌(header.payload.签名)
此令牌总是带来错误(无效签名)。参见 https://jwt.io/
验证令牌的public密钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmv3Slq7ofruWhFRXmnvt
/4WQuoJtoF2UQMtXmsZAZSODalklN21lV9t1ECAXOyOQX7E2QF8RZfJow5ImeTM5
WWHDhvFcg1/rI6bPIkkp4+Lu4Ljo8IIfYkEbIHt8+yOumEqiA1cvBR1TbojHMl4C
XW8jS4y4g7U6ZNYqKxOh9yvX6yUE0WRSzffRNVvx+Z5SNpmyjOXH/8A8e9BpG8tl
tAwdbtLd7Z+hcr60IERSWgqxnzUwzFWqdo4VNgLG68b1lKocbL8f0SnZiG0huyh0
tUEntR7PFWDePc2fOJmY9N9phgoD5FQjUQQiNipZi/Jw/z/BUz+utmQHwHNqyvCQ
ZQIDAQAB
-----END PUBLIC KEY-----
构建jwt的代码:
const kms = require('@google-cloud/kms');
const crypto = require('crypto');
const base64url = require('base64url');
async function main() {
const client = new kms.KeyManagementServiceClient({
keyFilename: "./googleCloudKey.json"
});
const projectId = '...';
const locationId = 'europe';
const keyRingId = '...';
const cryptoKeyId = '...';
const cryptoKeyVersion = '1';
const header = base64url(JSON.stringify({
"alg": "RS256",
"typ": "JWT",
"issuer": "login.myapp.com",
"audience": "*.myapp.com"
}));
const payload = base64url(JSON.stringify({
"userId": "1234567890",
"userName": "John Doe"
}));
const digest = crypto.createHash("sha256").update(Buffer.from(`${header}.${payload}`, "base64")).digest("base64");
const name = client.cryptoKeyVersionPath(
projectId,
locationId,
keyRingId,
cryptoKeyId,
cryptoKeyVersion
);
try {
const result = await client.asymmetricSign({
name: name,
digest: {
sha256: digest
}
});
const signature = base64url.fromBase64(result[0].signature.toString("base64"));
console.log("====== HEADER =====");
console.log(header);
console.log();
console.log("====== PAYLOAD =====");
console.log(payload);
console.log();
console.log("====== SIGNATURE =====");
console.log(signature);
console.log();
console.log();
console.log("===== JWT =====");
console.log(`${header}.${payload}.${signature}`);
} catch(e) {
console.error(e);
}
}
main().catch(console.error);
生成的令牌如下所示(= 最后一个 console.log
的输出):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImlzc3VlciI6ImxvZ2luLm15YXBwLmNvbSIsImF1ZGllbmNlIjoiKi5teWFwcC5jb20ifQ.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwidXNlck5hbWUiOiJKb2huIERvZSJ9.WVdM2NT5IGYKuCMV393yD7grA4GyVIrorL2OF-MHcRZESwPC3bOZIsx254IkMDInFyui74N6qEpHIe6UpR1JeuojMaGEANvSE0TtFpYgykU7xORmVEsjuZSYyKeEaTPAMwmXVPEKi5gQA9qlfQjTXE-h1xWYt2N3-pj2IHcgpgC-tarN1_TLNxZ5it2TrfpfGztI13L5WHYEFidExde9sxasvJsHZR3ax0wnoPn9V9rfqdXrEtG6-cdi9PAQprQClVOETtvpZNcCZpIlciHsaYBla5JjowbUmecSjQ54F-CuOggxvGvy16uG9p93ETlUyAknPTCGaMf9URyKkssYaw
在此代码段中:
Buffer.from(`${header}.${payload}`, "base64")
您正在对 header 和负载的串联进行 base64 解码。但 JWS 规范并不要求这样做。 https://www.rfc-editor.org/rfc/rfc7515#section-5.1