crypto.getRandomValues: назначение и ограничения

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

Главное отличие crypto.getRandomValues от обычных генераторов случайных чисел заключается в источнике энтропии. Значения формируются на основе системного CSPRNG (Cryptographically Secure PseudoRandom Number Generator), который использует аппаратные и системные источники шума: временные характеристики процессов, аппаратные события, состояние устройства и другие низкоуровневые данные.

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

Сигнатура и базовое использование

Метод работает только с типизированными массивами:

crypto.getRandomValues(typedArray)

Наиболее часто используются:

  • Uint8Array
  • Uint16Array
  • Uint32Array

Пример заполнения массива случайными значениями:

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

После выполнения каждый элемент массива будет содержать случайное целое число в диапазоне допустимого типа.

Поддерживаемые типы данных

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

Поддерживаются:

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

Не поддерживаются:

  • Float32Array
  • Float64Array

Причина заключается в отсутствии корректного и безопасного способа напрямую генерировать плавающую точку без риска потери равномерности распределения и появления артефактов представления IEEE 754.

Ограничение на размер буфера

Каждый вызов метода ограничен размером входного буфера. Максимальный объём данных, который может быть заполнен за один вызов, составляет 65 536 байт.

const largeBuffer = new Uint8Array(65536);
crypto.getRandomValues(largeBuffer);

Попытка передать массив большего размера приводит к исключению.

Это ограничение связано с безопасностью реализации и предотвращением потенциальных атак, связанных с массовым извлечением энтропии.

Синхронность выполнения

crypto.getRandomValues является синхронным методом. Он выполняется мгновенно и не возвращает Promise.

Это означает:

  • отсутствует асинхронный контекст
  • отсутствует задержка ожидания генерации
  • нельзя использовать await

С точки зрения производительности метод оптимизирован под быстрые вызовы, так как использует уже подготовленный пул энтропии операционной системы.

Безопасный контекст выполнения

Web Crypto API доступен только в защищённых контекстах:

  • HTTPS-сайты
  • localhost

В незащищённом контексте объект crypto может отсутствовать или быть ограничен, а вызов метода приведёт к ошибке.

Это требование связано с защитой от подмены и перехвата данных генерации в небезопасной среде.

Отличие от Math.random

Math.random() не подходит для криптографических задач. Он:

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

crypto.getRandomValues обеспечивает:

  • непредсказуемость
  • отсутствие внутреннего состояния, доступного JavaScript
  • использование системного источника энтропии

Пример различия:

Math.random(); // обычное псевдослучайное число
crypto.getRandomValues(new Uint8Array(1)); // криптографически стойкое значение

Особенности распределения значений

Метод заполняет массив байтами без дополнительной обработки. Это означает, что значения распределены равномерно в пределах диапазона типа (например, 0–255 для Uint8Array).

Однако при преобразовании значений в другие диапазоны может возникать проблема смещения (modulo bias). Например:

const arr = new Uint8Array(1);
crypto.getRandomValues(arr);

const value = arr[0] % 10;

Такой подход приводит к неравномерному распределению, поскольку 256 не делится на 10 без остатка. Для корректной нормализации требуется отбрасывание лишних значений или использование более сложных методов масштабирования.

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

На практике crypto.getRandomValues применяется как базовый строительный блок для:

  • генерации session ID
  • создания nonce
  • формирования salt для хеширования
  • подготовки ключевого материала (в сочетании с другими API Web Crypto)

Пример генерации случайного токена:

const bytes = new Uint8Array(32);
crypto.getRandomValues(bytes);

const token = Array.from(bytes)
  .map(b => b.toString(16).padStart(2, '0'))
  .join('');

Поведение при ошибках

Метод выбрасывает исключения в следующих случаях:

  • передан аргумент не являющийся типизированным массивом
  • используется неподдерживаемый тип (например, Float32Array)
  • превышен допустимый размер буфера

Пример ошибки:

crypto.getRandomValues(new Array(10)); // TypeError

Производительность и накладные расходы

Несмотря на обращение к системному источнику энтропии, метод оптимизирован для частого использования. Однако существуют практические ограничения:

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

Внутренние ограничения модели данных

Метод работает только с числовыми буферами фиксированного размера. Это исключает возможность:

  • генерации строк напрямую
  • генерации объектов
  • задания диапазона значений внутри метода

Все преобразования выполняются вручную после получения байтового массива.

Безопасность использования

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

Типичные ошибки:

  • использование Math.random() вместе с криптографическими данными
  • повторное использование одного и того же буфера
  • некорректное преобразование байтов в диапазоны
  • применение без учёта статистических искажений

Корректная модель использования предполагает, что crypto.getRandomValues используется только как источник первичной энтропии, а не как готовый генератор структурированных значений.

Особенности работы в разных окружениях

В браузерах реализация стандартизирована, но в серверных окружениях (например, через совместимые API или полифилы) поведение может отличаться. Важно учитывать:

  • различия в источниках энтропии
  • возможные ограничения sandbox-среды
  • различия в производительности системных генераторов

В современных браузерах метод считается стабильным и одинаковым по поведению в рамках спецификации WHATWG Web Crypto API.