Как проверить подписанный JWT с SubtleCrypto API Web Crypto? - PullRequest
0 голосов
/ 06 января 2019

Я пытаюсь проверить подпись 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 Ответ

0 голосов
/ 09 января 2019

Чтобы проверить 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'))
    )
}
...