Откуда берётся случайность
crypto.getRandomValues обращается к CSPRNG операционной системы (getrandom() в Linux, SecRandomCopyBytes в macOS, BCryptGenRandom в Windows), который инициализируется аппаратными событиями и, на современных CPU, инструкцией RDRAND. Он непредсказуем в обе стороны: знание миллиона выходных значений ничего не говорит о следующем. Math.random() таким не является: это быстрый PRNG с небольшим внутренним состоянием, годный для игр и никогда — для секретов.
Сколько байт
| Назначение | Байт | Почему |
|---|---|---|
| ID сессии, CSRF-токен | 16–32 | 128 бит недосягаемы для перебора; 32 байта — распространённое значение по умолчанию. |
| API-ключ / секрет | 32 | 256 бит; для хранения хешируется SHA-256, как пароль, но без необходимости в медленном хеше, поскольку он случайный. |
| Ключ подписи HMAC / JWT | 32–64 | Соответствует выходу хеша: 32 для SHA-256, 64 для SHA-512. |
| Ключ AES | 16 / 32 | AES-128 или AES-256. |
| Соль | 16 | Важна уникальность; 128 бит её гарантируют. |
| Токен сброса пароля в URL | 16–24 | Base64URL делает его коротким; храните его хеш, быстро истекайте срок. |
Случайные целые без смещения
Брать random_byte % 6 для кубика — тонкая ошибка: 256 не делится на 6, поэтому 1–4 выпадают чуть чаще, чем 5–6. Правильный метод берёт значение, отбрасывает его, если оно попадает в остаточный диапазон сверху, и пробует снова; так делает этот генератор, и так делают secrets.randbelow, crypto.randomInt и rand.Intn.
Ключи с префиксом
Префиксы вроде sk_live_, ghp_ или AKIA не добавляют безопасности, но делают ключи узнаваемыми в логах и позволяют сканерам секретов (GitHub, gitleaks) находить утёкшие. Выберите префикс, уникальный для вашего сервиса, и оставьте случайную часть размером 32 байта.
Вопросы
Это так же хорошо, как openssl rand или /dev/urandom?
Да: браузер вызывает тот же генератор операционной системы, который читают эти инструменты. Результат подходит для ключей и секретов. Если всё же нужно в shell: openssl rand -hex 32 или head -c 32 /dev/urandom | base64.
Хранить ли API-ключи в виде хешей?
Да, с быстрым хешем вроде SHA-256; поскольку ключ случайный, медленный парольный хеш не нужен. Покажите ключ один раз при создании и храните только хеш, как делают GitHub и Stripe.
Что такое Base64URL?
Base64 с - и _ вместо + и /, обычно без padding, чтобы значение могло находиться в URL или cookie без экранирования. Его используют JWT и большинство современных токенов.
Почему бы просто не использовать UUID как токен?
У UUIDv4 122 случайных бита, чего достаточно, но его фиксированный формат выдаёт, что это такое, и тратит символы на дефисы. Для секретов сырые случайные байты в Base64URL короче и стойче. UUID — для идентификаторов, а не для секретов.