Random bytes: примеры (PHP)
random_bytes(int $length): stringФункция random_bytes является встроенным генератором криптографически безопасных псевдослучайных байтов. Она появилась в PHP 7 и остается основным рекомендуемым способом для получения случайных данных, которые критичны для безопасности, таких как ключи, токены, соли или векторы инициализации.
Когда используется: Функция применяется во всех сценариях, требующих непредсказуемых и безопасных случайных значений. Это включает генерацию токенов подтверждения, криптографических ключей, соли для паролей, идентификаторов сессий и любых других случайных данных, где предсказуемость может привести к уязвимостям.
random_bytes(int $length): stringФункция принимает один обязательный аргумент:
- $length (int) - целое положительное число, определяющее количество байтов для генерации. Возвращаемая строка будет содержать ровно столько байтов.
Функция возвращает строку, состоящую из запрошенного количества случайных байтов. В случае ошибки (например, если не удалось получить достаточно энтропии) выбрасывается исключение типа \Exception, а в PHP 8.2+ - более специфичные \Random\RandomException или \ValueError для недопустимой длины.
Ниже приведены простые примеры генерации случайных байтов.
$bytes = random_bytes(16);
echo bin2hex($bytes); // Для удобного выводаПример результата: 1a2b3c4d5e6f7890a1b2c3d4e5f60718$key = random_bytes(32);
var_dump(base64_encode($key));Пример результата: string(44) "L0km9Pq7XjvWlNcRzTbYwAeFgHjKlMnOpQrStUvWxYz0="try {
$token = random_bytes(20);
} catch (\Exception $e) {
// Обработка ошибки (крайне маловероятна в нормальных условиях)
$token = openssl_random_pseudo_bytes(20); // Резервный вариант
}
echo 'Токен: ' . bin2hex($token);Пример результата: Токен: 8f9e7d6c5b4a39281726354433221100ffeeddcc- openssl_random_pseudo_bytes($length, &$crypto_strong) - генерирует псевдослучайную строку байт, используя OpenSSL. Второй аргумент позволяет проверить, был ли использован криптографически безопасный алгоритм. Использовать предпочтительно, если требуется совместимость со старыми версиями PHP (<7) или необходима интеграция с логикой OpenSSL.
- random_int($min, $max) - "сестра" функции random_bytes, генерирует криптографически безопасное случайное целое число в заданном диапазоне. Использовать предпочтительно для получения случайных чисел (например, для выбора элемента массива, генерации кода), а не сырых байтов.
- rand() и mt_rand() - старые генераторы псевдослучайных чисел. Они не являются криптографически безопасными и их предсказуемость высока. Использовать только в некритичных для безопасности задачах (например, симуляции, игры, тестовые данные).
import secrets
# Генерация 16 байт
bytes_data = secrets.token_bytes(16)
print(bytes_data.hex())c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0// Браузер и Node.js
const array = new Uint8Array(16);
crypto.getRandomValues(array);
console.log(Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''));1f2e3d4c5b6a7988f7e6d5c4b3a29180-- Генерация 32 байт, результат в бинарном виде
SELECT HEX(RANDOM_BYTES(32)) as random_data;random_data
----------------------------------
A1B2C3D4E5F67890123456789ABCDEF0...Отличия от PHP: В Python и JS (Web Crypto) подход похож - есть выделенный криптографический API. В MySQL функция работает в контексте СУБД. Главное отличие PHP - в простом и унифицированном синтаксисе без необходимости инициализации сложных объектов.
// PHP 8+
try {
$data = random_bytes(0); // Длина должна быть >= 1
} catch (\ValueError $e) {
echo 'Ошибка: ' . $e->getMessage();
}Ошибка: random_bytes(): Argument #1 ($length) must be greater than 0try {
// Запрос очень большого объема данных может теоретически вызвать проблему
$huge = random_bytes(PHP_INT_MAX);
} catch (\Random\RandomException $e) { // PHP 8.2+
echo 'Не удалось получить безопасные случайные данные: ' . $e->getMessage();
} catch (\Exception $e) { // Для PHP < 8.2
echo 'Общая ошибка: ' . $e->getMessage();
}Не удалось получить безопасные случайные данные: Random number generation failed$bytes = random_bytes(4);
echo $bytes; // Прямой вывод может показать нечитаемые символы
echo 'Правильно: ' . bin2hex($bytes); // Так корректноПравильно: 4a5b6c7d- PHP 8.2: Введено новое исключение
\Random\RandomException, которое выбрасывается при неудачной генерации, вместо общего\Exception. Это позволяет более точно отлавливать ошибки, связанные именно с генерацией случайных чисел. - PHP 8.0: Для недопустимых аргументов (например, длина < 1) теперь выбрасывается исключение типа
\ValueError. В более ранних версиях это могло приводить к ошибкам уровняE_WARNING. - PHP 7.0: Функция
random_bytes()была первоначально введена как часть расширения CSPRNG (Cryptographically Secure Pseudo-Random Number Generator).
function generatePassword(int $length = 16): string {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-_=+[]{}|;:,.<>?';
$password = '';
$charCount = strlen($chars);
// Используем random_int для выбора символов на основе безопасных байтов
for ($i = 0; $i < $length; $i++) {
$password .= $chars[random_int(0, $charCount - 1)];
}
return $password;
}
echo generatePassword(12);Пример: kP8@m#dL2!vQfunction generateUUIDv4(): string {
$data = random_bytes(16);
// Установка версии (4) и варианта (RFC 4122)
$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // version 4
$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // variant RFC 4122
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
echo generateUUIDv4();Пример: 550e8400-e29b-41d4-a716-446655440000// Соль для password_hash с PASSWORD_DEFAULT (использует bcrypt)
$salt = random_bytes(16); // bcrypt внутренне использует 16 байт соли
$password = 'user_password123';
$hash = password_hash($password, PASSWORD_DEFAULT); // Соль генерируется автоматически и безопасно
// Но можно явно сгенерировать для других алгоритмов, например, для ручного HMAC
$manualSalt = base64_encode(random_bytes(32));
echo 'Соль для HMAC: ' . $manualSalt;Пример: Соль для HMAC: zXl4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKT$method = 'aes-256-cbc';
$ivLength = openssl_cipher_iv_length($method);
$iv = random_bytes($ivLength);
$data = 'Секретное сообщение';
$key = random_bytes(32); // Ключ для AES-256
$encrypted = openssl_encrypt($data, $method, $key, 0, $iv);
echo 'Зашифровано. IV (hex): ' . bin2hex($iv);IV (hex): 1234567890abcdef1234567890abcdeffunction rollDice(int $count, int $sides = 6): array {
$results = [];
for ($i = 0; $i < $count; $i++) {
$results[] = random_int(1, $sides);
}
return $results;
}
print_r(rollDice(5, 20)); // Бросить 5 двадцатигранных кубиковArray
(
[0] => 14
[1] => 3
[2] => 20
[3] => 8
[4] => 11
)