Fuzzing-тестирование (fuzz testing) — это метод автоматической генерации большого количества случайных или полуслучайных входных данных для выявления ошибок в обработке. В контексте библиотеки jose для JavaScript особое внимание уделяется парсерам и валидаторам токенов: JWT (JSON Web Token), JWS (JSON Web Signature) и JWE (JSON Web Encryption).
Основные задачи fuzzing-тестирования:
Парсеры библиотеки jose работают с чётко определёнными форматами:
header.payload.signatureКаждый сегмент кодируется в base64url и должен корректно декодироваться в JSON.
Fuzzing направлен на нарушение этих предположений:
Для JavaScript-проектов с jose часто используются:
jest или vitest для тестовfast-check, jsfuzz,
fuzzilli (для движков JS)Пример базовой интеграции с fast-check:
import fc from 'fast-check'
import { jwtVerify } from 'jose'
test('fuzz JWT parsing', async () => {
await fc.assert(
fc.asyncProperty(fc.string(), async (input) => {
try {
await jwtVerify(input, new TextEncoder().encode('secret'))
} catch (e) {
// Ожидаем, что ошибки возможны, но не должно быть крашей
expect(e).toBeInstanceOf(Error)
}
})
)
})
Ключевой принцип: любые входные данные допустимы, но система не должна аварийно завершаться.
Проверяется устойчивость к нарушению формата:
const malformedTokens = [
'',
'abc',
'a.b',
'a.b.c.d',
'....',
]
Цель — убедиться, что:
Тестируются ошибки декодирования:
fc.string().map(str => str.replace(/=/g, '')) // удаление padding
Проверяются:
+, /,
%)После декодирования токена происходит парсинг JSON:
const invalidJSON = [
'{"alg":}',
'{"alg":"HS256",}',
'{alg:"HS256"}',
]
Задача:
Особенно важен параметр alg:
const headers = [
{ alg: 'none' },
{ alg: '' },
{ alg: 'INVALID' },
{ alg: 'HS256', typ: null },
]
Проверяется:
alg: none атакPayload может содержать произвольные данные:
fc.record({
sub: fc.string(),
exp: fc.integer(),
admin: fc.boolean(),
data: fc.anything()
})
Проверяются:
exp,
nbf)Подпись может быть:
const token = `${header}.${payload}.invalidsignature`
Ожидаемое поведение:
Более продвинутый подход — моделирование последовательности операций:
fc.asyncProperty(fc.string(), async (secret) => {
const token = await new SignJWT({ foo: 'bar' })
.setProtectedHeader({ alg: 'HS256' })
.sign(new TextEncoder().encode(secret))
const mutated = token.replace(/\./g, '..')
await expect(jwtVerify(mutated, new TextEncoder().encode(secret)))
.rejects.toThrow()
})
Используется для повышения эффективности тестов:
Инструменты:
c8 или nyc для покрытияЦель — достичь:
Fuzzing позволяет выявить:
При работе с длинными строками base64
Через:
Например:
expaud или issНапример:
После обнаружения ошибки важно:
fast-check автоматически делает это:
fc.assert(property, { verbose: true })
Результат — минимальный пример, вызывающий ошибку.
Fuzzing может выполняться:
Пример:
npm run fuzz
С автоматическим:
Сравнение поведения jose с другими библиотеками:
jsonwebtokennode-joseЕсли одна библиотека принимает токен, а другая — нет, это повод для анализа.
Примеры мутаций:
function mutate(token) {
return token.slice(0, -1) + String.fromCharCode(Math.random() * 128)
}
Особенно сложный случай:
Fuzzing проверяет:
fast-check — property-based fuzzingAFL (через обёртки)libFuzzer (через WASM)jazzer.js — coverage-guided fuzzing для JSFuzzing — один из ключевых инструментов для:
Особенно важен в: