Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чим random_bytes відрізняється від mt_rand і як генерувати токени безпечно?

Для безпеки потрібна не просто «випадковість», а непередбачуваність: знаючи попередні значення, неможливо вгадати наступні.

Некриптографічні генератори - mt_rand(), rand(), uniqid(), lcg_value(), Math.random() у JavaScript:

  • побудовані для швидкості й рівномірного розподілу, а не для безпеки;
  • внутрішній стан відновлюється з кількох виходів - для Mersenne Twister (mt_rand) відомі інструменти, що за кількома значеннями обчислюють зерно й передбачають усі наступні;
  • uniqid() - це просто поточний час у мікросекундах: передбачуваний.

Криптографічно стійкі генератори (CSPRNG) - з джерела ентропії операційної системи:

random_bytes(32);                 // 32 випадкові байти
bin2hex(random_bytes(32));        // 64 hex-символи
random_int(100000, 999999);       // число в діапазоні - для кодів підтвердження
Str::random(40);                  // Laravel: на основі random_bytes
Str::password(16);                // Laravel: пароль з різними класами символів

PHP 8.2 також має ООП-API Random\Randomizer з рушієм Random\Engine\Secure (за замовчуванням).

Де потрібен CSPRNG: токени сесій і API, токени скидання пароля й підтвердження email, коди 2FA й одноразові паролі, CSRF-токени, ключі шифрування, солі (зазвичай генерує password_hash), ідентифікатори, що служать «секретом» (неперебірні посилання на документи).

Розмір має значення: 128 біт ентропії (16 байтів) - мінімум для токенів, що мають бути неперебірними; 256 біт - з запасом. Шестизначний код - лише ~20 біт, тож його захищає не випадковість, а обмеження спроб і короткий термін дії.

Пастки:

  • md5(time()), sha1(uniqid()), md5(rand()) - хешування не додає ентропії: передбачуване значення лишається передбачуваним;
  • зменшення діапазону через % (random_bytes + % 10) дає нерівномірний розподіл - для чисел використовувати random_int;
  • UUID як секрет: UUIDv4 має 122 випадкові біти і для більшості цілей годиться, якщо генерується CSPRNG. Але UUIDv7 (Laravel HasUuids, Str::uuid7()) містить мітку часу і менше випадкових бітів - як ідентифікатор він добрий, а як секретний токен - ні;
  • mt_srand() з фіксованим зерном у коді безпеки - повна передбачуваність.

У JavaScript для безпеки - crypto.getRandomValues() і crypto.randomUUID(), а не Math.random().

Докладніше в документації: PHP: random_bytes

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання