Случайность, которой можно доверять: secrets vs random

Криптография держится на случайных ключах и токенах. Но не всякая случайность одинаково полезна: модуль random в Python для секретов категорически не подходит.

Две разные случайности

Модуль random создан для игр и симуляций. Он быстрый, но предсказуемый: зная начальное состояние (seed), можно вычислить все «случайные» числа наперёд. Для метания кубика это нормально, для генерации пароля — катастрофа.

Модуль secrets создан специально для криптографии. Он берёт случайность у операционной системы и непредсказуем.

Демо: random предсказуем

import random

# Если злоумышленник угадал seed — он знает ВСЕ числа
random.seed(42)
tokens_a = [random.randint(1000, 9999) for _ in range(5)]

random.seed(42)  # тот же seed
tokens_b = [random.randint(1000, 9999) for _ in range(5)]

print("Первый запуск: ", tokens_a)
print("Второй запуск: ", tokens_b)
print("Совпадают полностью:", tokens_a == tokens_b)
print("=> random ВОСПРОИЗВОДИМ, для секретов опасен")

Если сервер генерирует токены сброса пароля через random, а атакующий вычислит seed, он предскажет чужие токены и угонит аккаунты. Такое реально случалось.

Демо: secrets для секретов

import secrets
import string

# Криптостойкий пароль
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for _ in range(16))
print("Случайный пароль:", password)

# Случайный токен (например, ссылка сброса пароля)
token = secrets.token_urlsafe(16)
print("URL-токен:       ", token)

# Случайные байты для ключа
key = secrets.token_bytes(16)
print("Ключ (hex):      ", key.hex())

# Безопасный выбор: подбросить честную монетку
print("Монетка:         ", secrets.choice(["орёл", "решка"]))

Правило простое

ЗадачаЧем брать
Игра, симуляция, перемешать списокrandom
Пароль, ключ, токен, код подтвержденияsecrets

Запомни: если случайность защищает что-то важное — всегда secrets (или os.urandom). Никогда random.

Вывод:

random предсказуем: зная seed, можно вычислить все его числа — для секретов это дыра. secrets берёт непредсказуемую случайность у ОС. Пароли, токены и ключи — только через secrets.
Проверьте себя
1. Почему модуль random нельзя использовать для генерации паролей и токенов?
AОн слишком медленный
BОн предсказуем: зная seed, можно вычислить все его «случайные» числа
CОн умеет работать только с буквами
DОн требует подключения к интернету
2. Чем правильно генерировать токен ссылки для сброса пароля?
Arandom.randint
Bsecrets.token_urlsafe
Cdatetime.now
Dпросто числом 12345
Поддержать проект