Типичные ошибки при работе с рандомизацией

Одна из ключевых ошибок при работе с Web Crypto API заключается в смешивании криптографически стойкой генерации случайных чисел и псевдослучайных функций языка JavaScript.

Вместо использования crypto.getRandomValues() часто продолжают применять:

  • Math.random()
  • Date.now()
  • комбинации арифметических операций над временем или индексами

Эти источники не обладают криптографической стойкостью. Они предсказуемы при достаточном наблюдении за системой и не подходят для генерации токенов, ключей, nonce и других значений безопасности.


Использование неподходящих типов данных

crypto.getRandomValues() работает только с ограниченным набором типизированных массивов:

  • Int8Array
  • Uint8Array
  • Int16Array
  • Uint16Array
  • Int32Array
  • Uint32Array

Попытка передать:

  • обычный массив Array
  • BigInt64Array
  • Float32Array / Float64Array

приводит либо к ошибке выполнения, либо к неочевидной деградации логики генерации.

Особенно критична ошибка с числами с плавающей точкой: разработчики иногда пытаются напрямую получать случайные float значения, нарушая принцип дискретной энтропии Web Crypto API.


Ошибки при преобразовании байтов в числа

Частая проблема возникает при попытке преобразовать случайные байты в диапазон значений:

const arr = new Uint8Array(1);
crypto.getRandomValues(arr);
const value = arr[0] % 10;

Такая реализация приводит к смещению распределения (modulo bias).

Если диапазон не является делителем 256, некоторые значения будут появляться чаще других.

Корректные подходы требуют:

  • отбрасывания значений вне диапазона
  • или использования алгоритмов без смещения (rejection sampling)

Модульное смещение (modulo bias)

Наиболее распространённая логическая ошибка:

random = crypto.getRandomValues(new Uint8Array(1))[0] % N;

Проблема возникает всегда, когда:

  • 256 не делится на N без остатка

Например:

  • N = 10 → 256 % 10 = 6 лишних значений распределяются неравномерно
  • N = 7 → искажение ещё более выражено

Это приводит к статистически предсказуемым перекосам, критичным в:

  • генерации токенов
  • лотереях
  • распределении доступа
  • игровых механиках

Ошибки при генерации диапазона чисел

Попытка масштабирования байтовой случайности через умножение:

const value = crypto.getRandomValues(new Uint32Array(1))[0] / 2**32 * max;

выглядит корректно, но содержит скрытые проблемы:

  • потеря равномерности из-за округлений IEEE 754
  • снижение энтропии при больших диапазонах
  • некорректное поведение при целочисленных ограничениях

Для криптографических задач подобная схема считается нежелательной.


Использование Math.random в криптографических контекстах

Типичная ошибка архитектуры:

  • генерация session ID
  • токенов подтверждения
  • reset-password ссылок

с использованием:

Math.random().toString(36)

Math.random():

  • не использует системную энтропию
  • может быть воспроизведён при анализе состояния PRNG
  • зависит от реализации движка JavaScript

В контексте Web Crypto API это считается фундаментально неправильной заменой.


Ошибки повторного использования буферов

Хотя повторное использование TypedArray допустимо, логическая ошибка возникает при:

  • предположении, что буфер “накопит энтропию”
  • попытке переиспользовать частично заполненные массивы
const buf = new Uint8Array(16);

crypto.getRandomValues(buf);
// ожидание: "улучшение" случайности при повторном вызове
crypto.getRandomValues(buf);

Каждый вызов полностью перезаписывает данные. Частичное заполнение или “накопительный эффект” отсутствует, что часто неправильно учитывается в архитектуре.


Ошибки при генерации криптографических ключей

Распространённое заблуждение — использование случайных байтов как полноценного ключа без учета алгоритма:

const key = crypto.getRandomValues(new Uint8Array(16));

Проблема:

  • алгоритмы требуют строго определённой структуры ключа
  • длина ≠ корректность ключа
  • отсутствие derivation (PBKDF2, HKDF) делает ключи слабоуправляемыми

Особенно критично при:

  • AES ключах
  • HMAC секретах
  • JWT signing keys

Неправильная работа с nonce и IV

Частая ошибка — повторное использование nonce:

  • AES-GCM
  • ChaCha20-Poly1305
const iv = crypto.getRandomValues(new Uint8Array(12));

Ошибка возникает не в генерации, а в архитектуре:

  • повторное использование IV разрушает безопасность шифрования
  • разработчики часто кешируют IV для “оптимизации”

В криптографии это приводит к утечке информации о plaintext.


Ошибки при работе в серверных и клиентских средах

При миграции кода между Node.js и браузером возникают различия:

  • window.crypto vs globalThis.crypto
  • различия polyfill-реализаций
  • fallback на crypto.randomBytes в Node.js

Типичная ошибка:

  • предположение, что поведение идентично во всех средах

Это приводит к:

  • несовместимости форматов
  • различной энтропии в разных окружениях
  • скрытым багам в распределённых системах

Ошибки сериализации случайных данных

При передаче случайных значений через API часто происходит:

  • преобразование Uint8Array в строку через toString()
  • использование UTF-8 интерпретации байтов
const bytes = crypto.getRandomValues(new Uint8Array(16));
const token = bytes.toString();

Результат:

  • потеря данных
  • коллизии
  • деградация энтропии

Корректная практика требует явного кодирования:

  • Base64
  • Hex encoding

Ошибки в алгоритмах перемешивания (shuffle)

Неправильная реализация Fisher–Yates shuffle часто комбинируется с Math.random():

array.sort(() => Math.random() - 0.5);

Проблемы:

  • неравномерность перестановок
  • зависимость от внутреннего алгоритма сортировки
  • нарушение статистической корректности

Даже при замене на crypto.getRandomValues ошибка сохраняется, если алгоритм перестановки реализован неверно.


Ложное чувство безопасности

Использование Web Crypto API часто создаёт иллюзию безопасности:

  • “если используется crypto — значит безопасно”
  • игнорирование логики распределения значений
  • отсутствие анализа вероятностных смещений

Однако API гарантирует только источник энтропии, но не:

  • корректность преобразования
  • отсутствие bias
  • правильную архитектуру использования

Ошибки масштабирования случайности

Попытки расширить диапазон:

const rand = crypto.getRandomValues(new Uint32Array(1))[0] * 1000;

приводят к:

  • переполнению диапазонов
  • неравномерному распределению
  • потере младших битов энтропии

Особенно критично при:

  • генерации идентификаторов
  • распределении нагрузки
  • выборе случайных индексов в больших массивах

Игнорирование статистической проверки распределения

Редко учитывается необходимость проверки качества генерации:

  • chi-square тесты
  • анализ распределения битов
  • проверка на корреляции

Отсутствие проверки приводит к тому, что ошибки остаются незамеченными даже в production-системах, особенно при малых выборках.