Одна из ключевых ошибок при работе с Web Crypto API заключается в смешивании криптографически стойкой генерации случайных чисел и псевдослучайных функций языка JavaScript.
Вместо использования crypto.getRandomValues() часто
продолжают применять:
Math.random()Date.now()Эти источники не обладают криптографической стойкостью. Они предсказуемы при достаточном наблюдении за системой и не подходят для генерации токенов, ключей, nonce и других значений безопасности.
crypto.getRandomValues() работает только с ограниченным
набором типизированных массивов:
Int8ArrayUint8ArrayInt16ArrayUint16ArrayInt32ArrayUint32ArrayПопытка передать:
ArrayBigInt64ArrayFloat32Array / Float64Arrayприводит либо к ошибке выполнения, либо к неочевидной деградации логики генерации.
Особенно критична ошибка с числами с плавающей точкой: разработчики
иногда пытаются напрямую получать случайные float значения,
нарушая принцип дискретной энтропии Web Crypto API.
Частая проблема возникает при попытке преобразовать случайные байты в диапазон значений:
const arr = new Uint8Array(1);
crypto.getRandomValues(arr);
const value = arr[0] % 10;
Такая реализация приводит к смещению распределения (modulo bias).
Если диапазон не является делителем 256, некоторые значения будут появляться чаще других.
Корректные подходы требуют:
Наиболее распространённая логическая ошибка:
random = crypto.getRandomValues(new Uint8Array(1))[0] % N;
Проблема возникает всегда, когда:
Например:
Это приводит к статистически предсказуемым перекосам, критичным в:
Попытка масштабирования байтовой случайности через умножение:
const value = crypto.getRandomValues(new Uint32Array(1))[0] / 2**32 * max;
выглядит корректно, но содержит скрытые проблемы:
Для криптографических задач подобная схема считается нежелательной.
Типичная ошибка архитектуры:
с использованием:
Math.random().toString(36)
Math.random():
В контексте Web Crypto API это считается фундаментально неправильной заменой.
Хотя повторное использование TypedArray допустимо,
логическая ошибка возникает при:
const buf = new Uint8Array(16);
crypto.getRandomValues(buf);
// ожидание: "улучшение" случайности при повторном вызове
crypto.getRandomValues(buf);
Каждый вызов полностью перезаписывает данные. Частичное заполнение или “накопительный эффект” отсутствует, что часто неправильно учитывается в архитектуре.
Распространённое заблуждение — использование случайных байтов как полноценного ключа без учета алгоритма:
const key = crypto.getRandomValues(new Uint8Array(16));
Проблема:
Особенно критично при:
Частая ошибка — повторное использование nonce:
const iv = crypto.getRandomValues(new Uint8Array(12));
Ошибка возникает не в генерации, а в архитектуре:
В криптографии это приводит к утечке информации о plaintext.
При миграции кода между Node.js и браузером возникают различия:
window.crypto vs globalThis.cryptocrypto.randomBytes в Node.jsТипичная ошибка:
Это приводит к:
При передаче случайных значений через API часто происходит:
Uint8Array в строку через
toString()const bytes = crypto.getRandomValues(new Uint8Array(16));
const token = bytes.toString();
Результат:
Корректная практика требует явного кодирования:
Неправильная реализация Fisher–Yates shuffle часто комбинируется с
Math.random():
array.sort(() => Math.random() - 0.5);
Проблемы:
Даже при замене на crypto.getRandomValues ошибка
сохраняется, если алгоритм перестановки реализован неверно.
Использование Web Crypto API часто создаёт иллюзию безопасности:
Однако API гарантирует только источник энтропии, но не:
Попытки расширить диапазон:
const rand = crypto.getRandomValues(new Uint32Array(1))[0] * 1000;
приводят к:
Особенно критично при:
Редко учитывается необходимость проверки качества генерации:
Отсутствие проверки приводит к тому, что ошибки остаются незамеченными даже в production-системах, особенно при малых выборках.