And*_*son 4 javascript jwt webcrypto-api
我正在尝试使用 Web Crypto API 的 SubtleCrypto 接口验证 JWT 的签名。
我的代码不会验证令牌签名,而 JWT.io 上的调试工具会,我不知道为什么。这是我的验证功能:
function verify (jwToken, jwKey) {
const partialToken = jwToken.split('.').slice(0, 2).join('.')
const signaturePart = jwToken.split('.')[2]
const encoder = new TextEncoder()
return window.crypto.subtle
.importKey('jwk', jwKey, {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: 'SHA-256' }
}, false, ['verify'])
.then(publicKey =>
window.crypto.subtle.verify(
{ name: 'RSASSA-PKCS1-v1_5' },
publicKey,
encoder.encode(atob(signaturePart)),
encoder.encode(partialToken)
).then(isValid => alert(isValid ? 'Valid token' : 'Invalid token'))
)
}
Run Code Online (Sandbox Code Playgroud)
我希望该代码能够工作并提供对正确签名的 JWT 的肯定验证。相反,示例代码无法验证签名令牌。这个例子在我的 Chrome 71 中失败了。
我还使用来自 RFC 7520 的示例数据设置了一些测试。
要使用 SubtleCrypto 验证 JWS,您需要小心地在二进制和 base64url 表示之间正确编码和解码数据。不幸的是,标准实现中的浏览器btoa()和atob()用,因为它们使用“包含该范围内U + 0000到U + 00FF只有字符的Unicode字符串,每一个代表具有值分别为0x00〜0xFF一个二进制字节”为表示是难以工作二进制数据。
在 Javascript 中表示二进制数据的更好解决方案是使用 ES6 对象TypedArray并使用 Javascript 库(或自己编写编码器)将它们转换为符合RFC 4648 的base64url 。
旁注:base64 和 base64url 之间的区别在于标准中为值 62 和 63 选择的字符,base64 将它们编码为
+和,/而 base64url 编码-和_。
Javascript 中此类库的一个示例是rfc4648.js。
import { base64url } from 'rfc4648'
async function verify (jwsObject, jwKey) {
const jwsSigningInput = jwsObject.split('.').slice(0, 2).join('.')
const jwsSignature = jwsObject.split('.')[2]
return window.crypto.subtle
.importKey('jwk', jwKey, {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: 'SHA-256' }
}, false, ['verify'])
.then(key=>
window.crypto.subtle.verify(
{ name: 'RSASSA-PKCS1-v1_5' },
key,
base64url.parse(jwsSignature, { loose: true }),
new TextEncoder().encode(jwsSigningInput))
).then(isValid => alert(isValid ? 'Valid token' : 'Invalid token'))
)
}
Run Code Online (Sandbox Code Playgroud)