Как создаются случайные строки
Каждый символ выбирается независимо из выбранных вами символов с помощью crypto.getRandomValues — криптографически надёжного генератора случайных чисел браузера, того же источника, что используется для ключей шифрования. Простое случайное число по модулю количества символов сделало бы некоторые символы чуть вероятнее; эта страница выбирает заново, если случайное значение попадает в неравномерный остаток, поэтому у каждого символа ровно одинаковые шансы. Стойкость строки измеряется в битах энтропии:
bits = length × log2(characters to choose from) 32 × log2(62) = 32 × 5.954 ≈ 190.5 bits
Каждый бит вдвое увеличивает число попыток, которое нужно злоумышленнику. Префикс вроде sk_ ничего не добавляет, потому что он одинаков во всех строках; исключение похожих символов немного снижает стойкость, потому что выбирать приходится из меньшего числа символов. Math.random(), который используют многие быстрые генераторы, ненадёжен: его результат можно предсказать по прежним значениям.
Пример
В строке из 32 букв и цифр на каждый символ приходится 62 варианта, поэтому 32 × log2(62) ≈ 190,5 бита: угадать невозможно. 32 hex-символа несут 32 × 4 = 128 бит, как 16 случайных байт. Base64url использует 64 символа по 6 бит каждый, поэтому 43 символа вмещают 258 бит — столько получается при кодировании 32 случайных байт. У 6-значного кода всего миллион вариантов (19,9 бита): в списке из 500 таких кодов вероятность того, что два совпадут, уже около 11,7 %.
На сервере
Чтобы создавать случайные строки на сервере Linux или в скрипте развёртывания, используйте защищённый системный источник случайных чисел /dev/urandom через openssl или tr:
openssl rand -hex 16 # 32 hex characters
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='
head -c 500 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32Вопросы
Надёжны ли эти случайные строки?
Да. Они создаются функцией crypto.getRandomValues — криптографически надёжным генератором случайных чисел вашего браузера, и каждый символ выбирается без смещения. Строки создаются на вашем устройстве и не отправляются на сервер, так что никто другой их не видит. Для ключей и токенов берите не меньше 128 бит энтропии, например 22 буквы и цифры или 32 hex-символа.
Как сгенерировать случайную строку из 32 символов?
Оставьте длину 32 — она задана по умолчанию — и выберите символы: буквы и цифры дают около 190 бит, hex — ровно 128. На сервере openssl rand -hex 16 выводит 32 случайных hex-символа. В Python: secrets.token_hex(16) или secrets.token_urlsafe(24) для 32 символов Base64url.
Какой длины должен быть случайный ключ API или токен?
Не менее 128 бит энтропии, чтобы его нельзя было угадать даже при миллиардах попыток в секунду. Это 22 буквы и цифры, 32 hex-символа или 22 символа Base64url. Многие сервисы используют от 32 до 40 символов с префиксом вроде sk_, который показывает, для чего нужен ключ, и помогает сканерам секретов находить утёкшие ключи.
Чем отличаются строки hex и Base64url?
Hex использует 16 символов (0–9 и a–f), поэтому каждый несёт 4 бита. Base64url использует 64 (буквы, цифры, - и _), поэтому каждый несёт 6 бит, а строка при той же стойкости на треть короче. Оба варианта безопасны в URL, именах файлов и конфигурациях. Hex удобнее читать; Base64url компактнее.
Могут ли две сгенерированные строки совпасть?
При достаточной длине практически никогда: для 128-битных строк нужно около 2^64 из них, 18 миллиардов миллиардов, прежде чем повтор станет вероятным. Короткие строки повторяются раньше, чем можно подумать, из-за парадокса дней рождения: среди 500 шестизначных кодов два совпадают примерно в 12 % случаев. Страница предупреждает, если повтор в вашем списке вероятен.