Источники энтропии в браузере и Node.js

Криптографические операции в JavaScript напрямую зависят от качества источника случайности. Любая система шифрования, генерации ключей, соли или IV (initialization vector) опирается на энтропию — непредсказуемость данных, которые невозможно воспроизвести атакующему. В контексте CryptoJS этот вопрос особенно важен, поскольку библиотека исторически создавалась как универсальное решение, работающее как в браузере, так и в Node.js, где модели получения случайных данных существенно различаются.

Энтропия в криптографическом смысле — это мера неопределённости источника данных. Чем выше энтропия, тем сложнее предсказать результат генерации случайных чисел. В криптосистемах низкая энтропия приводит к уязвимостям: восстановлению ключей, предсказуемым IV, повторяющимся nonce и компрометации алгоритмов шифрования.

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


Источники энтропии в браузере

Браузерная среда предоставляет ограниченный, но стандартизированный набор инструментов для получения криптографически стойкой случайности.

Web Crypto API

Основным источником энтропии в современных браузерах является Web Crypto API, а именно метод:

  • crypto.getRandomValues()

Этот метод обращается к системному криптографическому генератору случайных чисел (CSPRNG), предоставляемому операционной системой. Его характеристики:

  • непредсказуемость выходных данных;
  • устойчивость к статистическому анализу;
  • запрет на повторяемость последовательностей;
  • аппаратная поддержка (в некоторых ОС — через hardware RNG).

Пример логики использования:

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

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


Ограничения браузерной модели

Несмотря на криптографическую стойкость, браузерная модель имеет особенности:

  • доступ к crypto.getRandomValues() может быть ограничен в небезопасных контекстах (HTTP вместо HTTPS);
  • невозможность контролировать внутренний алгоритм CSPRNG;
  • зависимость от реализации браузера и операционной системы;
  • отсутствие гарантированной однородности между различными платформами.

В старых окружениях (например, Internet Explorer или устаревшие WebView) CryptoJS может использовать fallback-методы, основанные на менее надёжных источниках.


Устаревшие источники энтропии

До появления Web Crypto API часто использовались:

  • Math.random()
  • временные метки (Date.now())
  • события мыши и клавиатуры

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

CryptoJS в современных сборках избегает их использования, однако в legacy-окружениях они могут присутствовать через пользовательские конфигурации.


Источники энтропии в Node.js

Node.js предоставляет более прямой доступ к системным криптографическим механизмам, чем браузер. Основной источник случайности реализован в модуле crypto.

crypto.randomBytes

Главный механизм генерации энтропии:

  • crypto.randomBytes(size)

Он использует системный CSPRNG, аналогичный тем, что применяются в ядре ОС.

Свойства:

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

Пример:

const crypto = require('crypto');
const buffer = crypto.randomBytes(16);

CryptoJS в Node.js часто интегрируется с этим источником через адаптер:

CryptoJS.lib.WordArray.random = function(nBytes) {
  return CryptoJS.enc.Hex.parse(
    crypto.randomBytes(nBytes).toString('hex')
  );
};

crypto.randomFillSync и randomFill

Более низкоуровневые функции:

  • crypto.randomFillSync(buffer)
  • crypto.randomFill(buffer, callback)

Они позволяют заполнять уже выделенные буферы случайными данными.

Особенности:

  • минимизация накладных расходов на аллокацию;
  • возможность асинхронного выполнения;
  • более гибкое управление памятью.

Источники энтропии на уровне ОС

Node.js не генерирует случайность самостоятельно. Он опирается на системные механизмы:

  • /dev/urandom в Unix-подобных системах;
  • CryptGenRandom / BCryptGenRandom в Windows;
  • аппаратные генераторы случайных чисел (HRNG), если доступны.

Эти источники агрегируют шум системы:

  • задержки дисков;
  • сетевые события;
  • аппаратные тайминги;
  • прерывания процессора.

Сравнение браузерной и серверной модели

Уровень контроля

  • браузер: ограниченный, абстрагированный доступ;
  • Node.js: прямой доступ к системным API.

Предсказуемость

  • оба окружения используют CSPRNG;
  • Node.js обычно имеет более стабильную реализацию без ограничений sandbox.

Производительность

  • браузер: оптимизирован через Web Crypto API;
  • Node.js: оптимизирован через нативные bindings.

Роль энтропии в CryptoJS

CryptoJS не содержит собственного криптографически стойкого генератора случайных чисел. Это принципиальное архитектурное решение:

  • библиотека реализует алгоритмы (AES, SHA, HMAC);
  • источники случайности предоставляются средой выполнения;
  • безопасность зависит от корректной интеграции с платформенными API.

Наиболее чувствительные операции:

  • генерация соли для PBKDF2;
  • создание IV для AES;
  • формирование ключевого материала;
  • создание nonce в потоковых режимах шифрования.

Типовые ошибки при работе с энтропией

Использование Math.random

Несмотря на удобство, этот генератор:

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

Повторное использование IV

Даже при наличии сильной энтропии ошибка повторного использования IV:

  • разрушает семантическую безопасность AES-CBC и GCM;
  • позволяет атакующему восстанавливать структуру данных.

Недостаточная длина случайных значений

Слабые ключи и короткие соли:

  • уменьшают пространство поиска;
  • ускоряют атаки перебора;
  • снижают эффективность PBKDF2 и аналогов.

Интеграция CryptoJS с внешними источниками энтропии

Для обеспечения корректной криптографической стойкости в реальных приложениях часто выполняется переопределение генератора случайных чисел:

CryptoJS.lib.WordArray.random = function(nBytes) {
  const bytes = crypto.randomBytes(nBytes);
  return CryptoJS.enc.Hex.parse(bytes.toString('hex'));
};

В браузере аналогичная интеграция:

CryptoJS.lib.WordArray.random = function(nBytes) {
  const array = new Uint8Array(nBytes);
  crypto.getRandomValues(array);
  return CryptoJS.enc.Hex.parse(Array.from(array).map(b => b.toString(16).padStart(2, '0')).join(''));
};

Такая интеграция обеспечивает:

  • единый криптографический стандарт между средами;
  • исключение небезопасных fallback-источников;
  • контроль над качеством энтропии на уровне приложения.

Практическое значение энтропии для криптосистем

Качество случайности напрямую влияет на устойчивость следующих механизмов:

  • симметричное шифрование (AES);
  • генерация ключей (PBKDF2, scrypt);
  • цифровые подписи (ECDSA nonce);
  • протоколы обмена ключами.

Слабая энтропия в любом из этих элементов приводит к системной компрометации даже при корректной реализации алгоритма.


Архитектурное различие подходов

Браузерная модель ориентирована на безопасность через ограничение доступа:

  • разработчик не управляет источником энтропии;
  • система гарантирует использование Web Crypto API.

Node.js модель ориентирована на расширяемость:

  • разработчик может подменять источник случайности;
  • возможна интеграция с внешними HSM и аппаратными RNG;
  • требуется самостоятельный контроль корректности.

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