export const prerender = true; Что такое криптографически стойкая случайность и почему это важно
EN RU Блог О проекте Конфиденциальность
randify

Что такое криптографически стойкая случайность и почему это важно

Обновлено

Каждый раз, когда вы придумываете пароль, выпускаете API-ключ или перемешиваете карты в онлайн-игре, вы полагаетесь на случайность. Но не вся случайность одинаково полезна. Разница между слабым псевдослучайным числом и криптографически стойкой случайностью часто определяет, останется ли система защищенной или окажется взломанной. Понимание того, как работает CSPRNG и почему безопасная генерация случайных чисел — это не абстракция, а инженерная необходимость, сегодня нужно любому разработчику, чье приложение хоть как-то касается чувствительных данных.

Вопрос встает остро: когда обычной случайности достаточно, а когда нужен именно CSPRNG? Ответ прост — всякий раз, когда от предсказуемости числа зависят деньги, данные или доступ.

Что такое криптографически стойкая случайность

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

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

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

Современные ядра Linux используют системный вызов getrandom(), который появился в версии 3.17 и стал предпочтительным способом получения энтропии в пользовательском пространстве. В отличие от прямого чтения /dev/urandom, getrandom() блокируется только до полной инициализации пула энтропии, после чего возвращает данные мгновенно.

В России использование криптографических средств в государственных информационных системах регулируется на законодательном уровне. Генераторы случайных чисел, применяемые в таких системах, должны проходить сертификацию ФСТЭК или ФСБ. Для коммерческих проектов барьер ниже, но принцип неизменен: доверять стоит только CSPRNG, прошедшим независимую экспертизу.

Почему Math.random недостаточно

Большинство языков предоставляют базовую функцию случайности для общих задач. В JavaScript Math.random() удобен для анимаций, игр и симуляций. Но он никогда не проектировался для безопасности. Его значения детерминированы: при том же начальном значении seed любой желающий воспроизведет всю последовательность.

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

Разработчики тянутся к Math.random() по привычке. Он знаком и не требует импортов. Но для аутентификации, шифрования или идентификаторов это неправильный инструмент. Цена инцидента безопасности всегда перевешивает экономию в одну строку кода.

Где это важно

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

Пароли и аутентификация

Когда вы используете Генератор паролей, вы рассчитываете на то, что результат будет неугадываемым. Если генератор опирается на слабый источник случайности, пароли начинают следовать предсказуемым паттернам. Злоумышленники предварительно вычисляют вероятные комбинации и взламывают аккаунты за минуты. Надежный CSPRNG гарантирует, что каждый символ выбирается из пула с максимальной энтропией.

Криптографические ключи и токены

API-ключи, сессионные токены и ключи шифрования должны быть уникальными и непредсказуемыми. Если два пользователя получат одинаковый токен, или если атакующий угадает следующий элемент последовательности, система скомпрометирована. CSPRNG гарантирует, что токены выбираются из пространства настолько огромного, что угадывание вычислительно невозможно.

Блокчейн и кошельки

В 2013 году несколько Android-приложений для Bitcoin-кошельков использовали дефектную реализацию SecureRandom в Java. Баг приводил к повторению случайных значений, что вело к дублированию криптографических подписей. Атакующие использовали эту слабость для кражи Bitcoin. Этот случай остается одним из самых дорогих напоминаний о том, что безопасная случайность не может быть второстепенной задачей.

UUID и идентификаторы

UUID версии 4, который вы можете создать через Генератор UUID, полностью строится на случайности. Если источник слаб, UUID теряют гарантии уникальности. Коллизии становятся вероятнее, базы данных повреждаются, а злоумышленники получают подсказки об архитектуре вашей инфраструктуры.

Хеширование и соли

Алгоритмы вроде bcrypt и Argon2 требуют уникальной соли для каждого хеша. При предсказуемых солях злоумышленники строят rainbow-таблицы и массово обращают хеши. Используя Генератор хешей или реализуя хеширование самостоятельно, всегда извлекайте соли из проверенного CSPRNG.

Практический чеклист

Вот как получить безопасную случайность в популярных средах.

Браузеры и фронтенд

Используйте Web Crypto API:

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

Этот метод доступен во всех современных браузерах и обращается напрямую к CSPRNG операционной системы. Для токенов и ключей Math.random() — не вариант.

Node.js

Используйте встроенный модуль crypto:

const crypto = require('crypto');
const bytes = crypto.randomBytes(32);

Под капотом вызывается OpenSSL, который читает из /dev/urandom на Linux или из эквивалентного источника на Windows и macOS.

Linux и Unix

Читайте напрямую из /dev/urandom. Это устройство взаимодействует с CSPRNG ядра и блокируется только при недостатке энтропии на самом раннем этапе загрузки. Для практически всех прикладных задач /dev/urandom — правильный выбор.

Python

Используйте модуль secrets, появившийся в Python 3.6:

import secrets
token = secrets.token_urlsafe(32)

Модуль secrets создан специально для задач, чувствительных к безопасности, и оборачивает CSPRNG ОС. Для паролей и токенов модуль random не подходит.

Go

В Go используйте пакет crypto/rand:

import "crypto/rand"

b := make([]byte, 32)
_, err := rand.Read(b)

Пакет crypto/rand читает из системного CSPRNG. Пакет math/rand подходит только для симуляций и игр.

Выводы

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

Считайте Math.random() и подобные удобные функции запретной зоной для задач безопасности. Вместо них используйте crypto.getRandomValues(), crypto.randomBytes(), /dev/urandom или secrets. Проверяйте, что сторонние библиотеки для генерации токенов, создания паролей или управления ключами тоже опираются на CSPRNG.

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

Похожие статьи