Компактное представление JSON Web Signature (JWS) состоит из трёх частей, разделённых точками:
BASE64URL(Protected Header) . BASE64URL(Payload) . BASE64URL(Signature)
alg) и дополнительные параметрыБиблиотека jose предоставляет метод
compactVerify для проверки корректности такой структуры и
подлинности подписи.
Для работы с compactVerify необходимо импортировать
функцию:
import { compactVerify } from 'jose'
Минимальный пример верификации:
const { payload, protectedHeader } = await compactVerify(jws, key)
Где:
jws — строка в компактном форматеkey — ключ для проверки подписи (секретный или
публичный)Метод compactVerify принимает различные типы ключей:
Uint8Array (для симметричных алгоритмов, например
HS256)CryptoKey (Web Crypto API)KeyObject (Node.js)Пример симметричного ключа:
const secret = new TextEncoder().encode('super-secret')
Пример асимметричного ключа:
import { importSPKI } from 'jose'
const publicKey = await importSPKI(spkiPem, 'RS256')
compactVerify возвращает объект:
{
payload: Uint8Array,
protectedHeader: { alg: string, ... }
}
payload — бинарное представление полезной нагрузкиprotectedHeader — объект с декодированным
заголовкомДля преобразования payload в строку:
const decoded = new TextDecoder().decode(payload)
import { compactVerify } from 'jose'
const jws = 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiam9obiJ9.xxxxxx'
const secret = new TextEncoder().encode('secret')
const { payload, protectedHeader } = await compactVerify(jws, secret)
console.log(protectedHeader.alg) // HS256
console.log(new TextDecoder().decode(payload)) // {"user":"john"}
compactVerify не ограничивает автоматически допустимые
алгоритмы. Проверка значения alg должна выполняться
явно:
if (protectedHeader.alg !== 'HS256') {
throw new Error('Недопустимый алгоритм')
}
Это критично для предотвращения атак подмены алгоритма.
Метод выбрасывает исключения в следующих случаях:
Пример обработки:
try {
await compactVerify(jws, key)
} catch (err) {
console.error('Ошибка верификации:', err)
}
Хотя compactVerify может использоваться для проверки
JWT, он не валидирует стандартные поля (exp,
nbf, iss). Для этого применяется
jwtVerify.
Тем не менее, базовая проверка возможна:
const { payload } = await compactVerify(token, key)
const claims = JSON.parse(new TextDecoder().decode(payload))
const jwk = {
kty: 'oct',
k: 'c2VjcmV0'
}
const { payload } = await compactVerify(jws, jwk)
compactVerify поддерживает функцию-резолвер ключа:
const getKey = async (protectedHeader) => {
if (protectedHeader.alg === 'RS256') {
return publicKey
}
throw new Error('Unknown alg')
}
await compactVerify(jws, getKey)
Это удобно при работе с JWKS или динамическими ключами.
Пример получения ключа из удалённого источника:
import { createRemoteJWKSet } from 'jose'
const JWKS = createRemoteJWKSet(new URL('https://example.com/.well-known/jwks.json'))
const { payload } = await compactVerify(jws, JWKS)
В этом случае ключ выбирается автоматически по kid из
заголовка.
Protected Header может содержать:
kid — идентификатор ключаtyp — тип токенаcty — тип содержимогоПример:
if (!protectedHeader.kid) {
throw new Error('Отсутствует kid')
}
1. Явная проверка алгоритма
Никогда не доверять значению alg без проверки.
2. Использование строгих ключей
3. Ограничение источников ключей
При использовании удалённых JWKS:
4. Проверка структуры payload
const data = JSON.parse(decoded)
if (typeof data.user !== 'string') {
throw new Error('Invalid payload')
}
| Метод | Назначение |
|---|---|
compactVerify |
Проверка JWS (низкий уровень) |
jwtVerify |
Проверка JWT + валидация claims |
generalVerify |
Проверка JWS в общем JSON формате |
compactVerify поддерживает все алгоритмы, реализованные
в jose:
Выбор алгоритма определяется заголовком JWS и типом ключа.
Библиотека jose универсальна:
crypto)compactVerify автоматически использует доступные
криптографические примитивы.
import { compactVerify, importSPKI } from 'jose'
const publicKey = await importSPKI(spkiPem, 'RS256')
const { payload } = await compactVerify(jws, publicKey)
console.log(new TextDecoder().decode(payload))
Факторы, влияющие на скорость:
Для высоконагруженных систем рекомендуется:
Проверка нескольких ключей:
const keys = [key1, key2]
const getKey = async () => {
for (const key of keys) {
try {
await compactVerify(jws, key)
return key
} catch {}
}
throw new Error('No valid key')
}
algconst { payload, protectedHeader } = await compactVerify(jws, key)
if (protectedHeader.alg !== 'HS256') {
throw new Error('Invalid alg')
}
const data = JSON.parse(new TextDecoder().decode(payload))
if (!data.user) {
throw new Error('Invalid payload')
}
Такой подход обеспечивает базовый уровень безопасности при работе с компактными JWS.