Для безпеки потрібна не просто «випадковість», а непередбачуваність: знаючи попередні значення, неможливо вгадати наступні.
Некриптографічні генератори - 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().