Хеширование паролей и соль
Серьёзные сайты не хранят твой пароль. Они хранят его хеш — и обязательно с солью.
Почему пароли нельзя хранить как есть
Если сайт хранит пароли открытым текстом и базу украдут, все пароли утекут мгновенно. Поэтому хранят не пароль, а его хеш. При входе сайт хеширует введённый пароль и сравнивает с сохранённым хешем — сам пароль ему знать не нужно.
import hashlib
def hash_password(password):
return hashlib.sha256(password.encode()).hexdigest()
stored = hash_password("qwerty123")
print("В базе хранится:", stored[:16], "...")
# при входе сравниваем хеши
attempt = "qwerty123"
print("Вход верный:", hash_password(attempt) == stored)Вывод:
В базе хранится: 9adf90... ... Вход верный: True
Проблема: одинаковые пароли — одинаковые хеши
Хеш детерминирован, поэтому два пользователя с паролем 123456 получат одинаковый хеш. Злоумышленник заранее считает хеши популярных паролей (это называется радужной таблицей) и просто ищет совпадения. Убедимся в уязвимости:
import hashlib
def h(p):
return hashlib.sha256(p.encode()).hexdigest()[:12]
print("user1 (123456):", h("123456"))
print("user2 (123456):", h("123456")) # тот же хеш!
print("Совпадают:", h("123456") == h("123456"))Вывод:
user1 (123456): 8d969eef6ec... user2 (123456): 8d969eef6ec... Совпадают: True
Решение: соль
Соль — это случайная строка, которую добавляют к паролю перед хешированием. У каждого пользователя своя соль. Тогда даже одинаковые пароли дают разные хеши, и радужные таблицы бесполезны.
import hashlib, secrets
def hash_with_salt(password, salt=None):
if salt is None:
salt = secrets.token_hex(8) # своя случайная соль
digest = hashlib.sha256((salt + password).encode()).hexdigest()
return salt, digest
salt1, h1 = hash_with_salt("123456")
salt2, h2 = hash_with_salt("123456")
print("Пароль одинаковый, а хеши разные:")
print("user1:", h1[:16], "соль:", salt1)
print("user2:", h2[:16], "соль:", salt2)
print("Хеши совпадают:", h1 == h2)Вывод:
Пароль одинаковый, а хеши разные: user1: 3f9c... соль: a1b2c3d4... user2: e72a... соль: 9f8e7d6c... Хеши совпадают: False
Соль хранят рядом с хешем (она не секретная — её задача только в том, чтобы хеши были разными). При проверке пароля берут ту же соль, хешируют введённый пароль и сравнивают.
В реальной жизни
Для паролей используют не просто SHA-256, а специально замедленные функции: bcrypt, scrypt, Argon2. Они намеренно работают медленно, чтобы перебор пароля занимал недопустимо много времени.