Сравнение с устаревшими подходами: Math.random, btoa/atob, сторонние библиотеки

Функция Math.random() долгое время использовалась как универсальный источник случайных чисел в JavaScript-приложениях. Она возвращает значение в диапазоне от 0 до 1, создавая иллюзию случайности, достаточной для большинства прикладных задач интерфейса и логики.

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

Главные ограничения Math.random():

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

В контексте безопасности это означает, что любые механизмы, основанные на Math.random(), могут быть скомпрометированы. Генерация токенов, ключей, одноразовых паролей или CSRF-защит с его использованием создаёт фундаментальную уязвимость.

Пример небезопасного подхода:

const token = Math.random().toString(36).substring(2);

Даже при внешней “достаточной случайности” такой токен может быть восстановлен или предсказан при наличии достаточного числа наблюдений.


btoa/atob и ложное представление о шифровании

Функции btoa() и atob() часто ошибочно воспринимаются как инструменты шифрования. На практике они реализуют только кодирование и декодирование Base64.

Base64 — это способ представления бинарных данных в текстовом виде, а не механизм защиты информации.

Ключевые особенности:

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

Пример типичного заблуждения:

const encoded = btoa("secret-password");
const decoded = atob(encoded);

Полученный результат не является защищённым ни в каком смысле. Любой, кто получил строку encoded, мгновенно восстанавливает исходные данные.

Часто btoa/atob ошибочно используют для:

  • “скрытия” токенов в клиентском коде
  • псевдошифрования параметров URL
  • маскировки чувствительных данных в localStorage

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


Сторонние криптографические библиотеки

До появления зрелой реализации Web Crypto API в браузерах широко использовались сторонние библиотеки:

  • CryptoJS
  • Forge
  • SJCL (Stanford JavaScript Crypto Library)
  • libsodium.js (порт libsodium на JavaScript/WASM)

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

Преимущества сторонних решений

  • наличие высокоуровневых API
  • поддержка множества алгоритмов (AES, HMAC, RSA)
  • кросс-платформенность (браузер + Node.js)
  • гибкость и расширяемость
  • предсказуемость API независимо от браузера

Недостатки подхода

  • увеличение размера бандла
  • необходимость ручного аудита безопасности
  • риск использования устаревших алгоритмов
  • реализация криптографии на чистом JavaScript (медленнее нативных решений)
  • возможные ошибки реализации (side-channel атаки, неправильное управление ключами)

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


Переход к Web Crypto API

Web Crypto API стал стандартизированным ответом браузеров на необходимость встроенной криптографии. В отличие от предыдущих подходов, он предоставляет нативные реализации криптографических операций, изолированные от JavaScript-слоя.

Ключевое отличие — работа через низкоуровневые системные реализации, а не через пользовательский код.

Генерация криптографически стойких случайных значений

Вместо Math.random() используется:

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

Этот метод:

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

Хэширование данных

Вместо сторонних библиотек:

const data = new TextEncoder().encode("message");

const hashBuffer = await crypto.subtle.digest("SHA-256", data);

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

  • поддержка SHA-1, SHA-256, SHA-384, SHA-512
  • асинхронная обработка
  • нативная реализация
  • отсутствие необходимости в внешних зависимостях

Симметричное шифрование

Web Crypto API предоставляет доступ к алгоритмам вроде AES-GCM:

const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true,
  ["encrypt", "decrypt"]
);

const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode("secret data");

const encrypted = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv },
  key,
  encoded
);

В отличие от сторонних библиотек:

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

Асимметричная криптография

Web Crypto API поддерживает RSA-OAEP и ECDSA:

const keyPair = await crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["encrypt", "decrypt"]
);

Это позволяет:

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

Сравнение подходов по ключевым параметрам

Криптографическая стойкость

  • Math.random — отсутствует
  • btoa/atob — отсутствует
  • сторонние библиотеки — зависит от реализации
  • Web Crypto API — гарантируется стандартом и OS-реализацией

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

  • Math.random — высокая, но нерелевантна для безопасности
  • btoa/atob — высокая, но не криптография
  • сторонние библиотеки — средняя или низкая (JS/WASM)
  • Web Crypto API — высокая (native implementation)

Безопасность реализации

  • Math.random — уязвим к предсказанию
  • btoa/atob — не обеспечивает защиту
  • сторонние библиотеки — риск ошибок реализации и аудита
  • Web Crypto API — минимизация ошибок за счёт стандартизированного API

Управление ключами

  • Math.random — отсутствует
  • btoa/atob — отсутствует
  • сторонние библиотеки — ручное управление, риск утечек
  • Web Crypto API — использование CryptoKey и ограниченного доступа

Практическое различие уровней абстракции

Исторически JavaScript развивался от полного отсутствия криптографических инструментов к нативной интеграции в браузер.

  • Math.random() — псевдослучайность для UI и логики
  • btoa/atob — кодирование данных без защиты
  • сторонние библиотеки — попытка компенсировать пробелы платформы
  • Web Crypto API — системный уровень криптографии внутри браузера

Фундаментальное изменение заключается в переносе ответственности: от разработчика и библиотек к платформе и операционной системе.


Ограничения старых подходов в современных условиях

Использование устаревших методов приводит к системным проблемам:

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

Особенно критично это проявляется в:

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

Изменение модели доверия

Переход к Web Crypto API фактически меняет модель доверия:

  • раньше доверие было к библиотеке
  • теперь доверие делегировано браузеру и ОС

Это снижает поверхность атаки и уменьшает вероятность ошибок, связанных с реализацией криптографии на уровне приложения.