我需要在ES256工作线程中验证Cloudflare JWT令牌。据我所知,他们在那里不运行Node.js,我将不得不使用Web Crypto API (也可以在浏览器中使用window.crypto.subtle)来使一切工作。然而,我希望以PEM文件的形式收到公钥,我认为我在导入它们时遇到了问题。
我一直在尝试修改现有的只支持HS256的开源JWT实现来支持ES256。
除了尝试使用实际的令牌和密钥,以及在浏览器和OpenSSL中生成的密钥之外,我还尝试使用JWT.io网站上的一个工作示例(在使用node-jose将其转换为JWK格式之后),因为它应该正确验证。但是我没有收到任何错误,我在浏览器中运行的代码只是告诉我令牌无效。
下面是我的Node REPL会话,我使用它将密钥从JWT.io转换为JWK:
> const jose = require('node-jose')
> const publicKey = `-----BEGIN PUBLIC KEY-----
... MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
... q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==
... -----END PUBLIC KEY-----`
> const keyStore = jose.JWK.createKeyStore()
> keyStore.add(publicKey, 'pem')
> keyStore.toJSON()
{
keys: [
{
kty: 'EC',
kid: '19J8y7Zprt2-QKLjF2I5pVk0OELX6cY2AfaAv1LC_w8',
crv: 'P-256',
x: 'EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84',
y: 'kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY'
}
]
}
>以下是失败的验证,基于webcrypto-jwt包中的代码:
function utf8ToUint8Array(str) {
// Adapted from https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/subtle/hmac/sign-verify.html
var Base64URL = {
stringify: function (a) {
var base64string = btoa(String.fromCharCode.apply(0, a));
return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
},
parse: function (s) {
s = s.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '');
return new Uint8Array(Array.prototype.map.call(atob(s), function (c) { return c.charCodeAt(0); }));
}
};
str = btoa(unescape(encodeURIComponent(str)));
return Base64URL.parse(str);
}
var cryptoSubtle = (crypto && crypto.subtle) ||
(crypto && crypto.webkitSubtle) ||
(window.msCrypto && window.msCrypto.Subtle);
// Token from JWT.io
var tokenParts = [
'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9',
'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0',
'tyh-VfuzIxCyGYDlkBA7DfyjrqmSHu6pQ2hoZuFqUSLPNY2N0mpHb3nk5K17HWP_3cYHBw7AhHale5wky6-sVA'
];
// Public key from JWT.io converted in Node using node-jose
var publicKey = {
kty: 'EC',
kid: '19J8y7Zprt2-QKLjF2I5pVk0OELX6cY2AfaAv1LC_w8',
crv: 'P-256',
x: 'EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84',
y: 'kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY'
};
var importAlgorithm = {
name: 'ECDSA',
namedCurve: 'P-256',
hash: 'SHA-256',
};
cryptoSubtle.importKey(
"jwk",
publicKey,
importAlgorithm,
false,
["verify"]
).then(function (key) {
var partialToken = tokenParts.slice(0,2).join('.');
var signaturePart = tokenParts[2];
cryptoSubtle.verify(
importAlgorithm,
key,
utf8ToUint8Array(signaturePart),
utf8ToUint8Array(partialToken)
).then(function (ok) {
if (ok) {
console.log("I think it's valid");
} else {
console.log("I think it isn't valid");
}
}).catch(function (err) {
console.log("error verifying", err);
});
}).catch(function(err) {
console.log("error importing", err);
});因为我从JWT.io复制了一个有效的密钥和一个有效的令牌,所以我希望代码能够记录“我认为它是有效的”而不会出现错误。实际上,它没有显示任何错误,但它最终出现在“我认为它无效”分支中。
发布于 2019-05-29 18:56:06
已在此处回答How to verify a signed JWT with SubtleCrypto of the Web Crypto API?
所以,如果我理解正确的话,问题是开源上游中包含的base64编码在其中一个方向上不能正常工作,因为它使用浏览器的btoa。相反,改编https://github.com/swansontec/rfc4648.js是可行的。
https://stackoverflow.com/questions/56357330
复制相似问题