Почему использование функции rand() в PHP для генерации паролей — это плохая идея и какую безопасную альтернативу использовать?

Функция rand() в PHP является генератором псевдослучайных чисел (PRNG), и её использование для генерации паролей или любых других криптографически значимых данных считается серьёзной уязвимостью безопасности. Разберём подробно, почему это так, и какие существуют безопасные альтернативы.

## Почему rand() небезопасна?

**1. Предсказуемость алгоритма.** rand() использует линейный конгруэнтный генератор или аналогичный алгоритм, который является детерминированным. Это означает, что при знании начального значения (seed) злоумышленник может воспроизвести всю последовательность «случайных» чисел. Если атакующий знает время запуска скрипта (а это нередко можно определить по HTTP-заголовкам или логам), он может перебрать ограниченное количество вариантов seed и восстановить сгенерированный пароль.

**2. Малое пространство состояний.** Внутреннее состояние rand() ограничено, что делает полный перебор всех возможных последовательностей реальным. Это кардинально отличается от криптографически стойкого генератора, который использует энтропию из системных источников.

**3. Отсутствие криптографической стойкости.** rand() не проектировалась для задач безопасности. Она оптимизирована для скорости и равномерного распределения, но не для непредсказуемости — ключевого требования криптографии.

**4. Атака на основе наблюдений.** Если злоумышленник получает несколько значений, сгенерированных rand() (например, через другие части приложения), он может восстановить состояние генератора и предсказать будущие значения, включая пароли.

## Безопасные альтернативы

**random_int() и random_bytes() (PHP 7+).** Это криптографически стойкие функции, которые используют системный CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). На Linux они обращаются к /dev/urandom или getrandom(), на Windows — к CryptGenRandom.

php
// Генерация случайного числа в диапазоне
$number = random_int(0, 9);

// Генерация случайных байт
$bytes = random_bytes(32);
$token = bin2hex($bytes);

**Пример генерации безопасного пароля:**

php
function generateSecurePassword(int $length = 16): string {
$chars = ‘abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()’;
$password = »;
$max = strlen($chars) — 1;
for ($i = 0; $i < $length; $i++) {
$password .= $chars[random_int(0, $max)];
}
return $password;
}

**openssl_random_pseudo_bytes().** Ещё один вариант, доступный в более ранних версиях PHP. Второй параметр указывает, был ли использован криптографически стойкий алгоритм.

php
$bytes = openssl_random_pseudo_bytes(32, $strong);
if (!$strong) {
throw new Exception('Не удалось получить криптографически стойкие случайные байты');
}

## Итог

Для любых задач, связанных с безопасностью — генерация паролей, токенов сброса пароля, CSRF-токенов, ключей API — всегда используйте random_int() или random_bytes(). Никогда не применяйте rand(), mt_rand() или array_rand() в криптографическом контексте. Разница между удобным и безопасным кодом здесь может стоить данных ваших пользователей.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.