Как проверить подписанный JWT с SubtleCrypto API Web Crypto?
Я пытаюсь проверить подпись JWT, используя интерфейс SubtleCrypto API Web Crypto.
Мой код не будет проверять подпись токена, в то время как инструмент отладки в 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'))
)
}
Я ожидал, что этот код сработает и обеспечит положительную проверку правильно подписанного JWT. Вместо этого пример кода не может проверить подписанный токен. Пример неудачного в Chrome 71 для меня.
Я также настроил некоторые тесты, используя пример данных из RFC 7520.
1 ответ
Чтобы проверить JWS с SubtleCrypto, вы должны быть осторожны, чтобы правильно кодировать и декодировать данные между двоичным представлением и представлением base64url. К сожалению стандартная реализация в браузере btoa()
а также atob()
с ними трудно работать, так как они используют "строку Unicode, содержащую только символы в диапазоне от U+0000 до U+00FF, каждый из которых представляет двоичный байт со значениями от 0x00 до 0xFF соответственно" в качестве представления двоичных данных.
Лучшим решением для представления двоичных данных в Javascript является использование объекта ES6 TypedArray
и используйте библиотеку Javascript (или напишите кодировщик самостоятельно), чтобы преобразовать их в base64url, который соответствует RFC 4648.
Примечание: разница между 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'))
)
}