Хеширование с солью¶
Хеширование с солью — это криптографический метод защиты паролей и других конфиденциальных данных, при котором к исходной строке перед вычислением хеш-функции добавляется случайная или псевдослучайная строка (соль). Этот подход предотвращает атаки по заранее вычисленным таблицам (радужным таблицам) и атаки на основе словарей, делая одинаковые пароли разных пользователей неразличимыми в хранилище хешей.
¶История и предпосылки
¶Проблема хранения паролей
В ранних компьютерных системах пароли хранились в открытом виде или в виде простых хешей (например, MD5 или SHA-1). Это делало их уязвимыми: при утечке базы данных злоумышленник мог мгновенно получить все пароли. Для ускорения подбора паролей использовались радужные таблицы — предварительно вычисленные таблицы хешей для миллионов комбинаций. Если два пользователя имели одинаковый пароль, их хеши совпадали, что упрощало атаку.
¶Введение соли
Метод хеширования с солью впервые был предложен в 1970-х годах в контексте операционной системы Unix. В Unix-подобных системах пароли хранились в файле /etc/passwd (позже — в /etc/shadow) в виде хеша с добавлением случайной соли. Соль сохранялась вместе с хешем, что позволяло системе при проверке пароля повторить процедуру. Этот подход стал стандартом де-факто для защиты паролей в Unix-системах и позже был адаптирован для многих других платформ.
¶Принцип работы
¶Алгоритм
Процесс хеширования с солью включает следующие шаги:
- Генерация соли: создаётся случайная строка фиксированной длины (обычно 16–32 байта). Соль должна быть уникальной для каждого пользователя и каждого пароля.
- Конкатенация: соль объединяется с исходным паролем (например,
salt + passwordилиpassword + salt). - Хеширование: полученная строка обрабатывается криптографической хеш-функцией (например, bcrypt, scrypt, Argon2, PBKDF2).
- Сохранение: в базе данных хранится пара
(соль, хеш). Соль не является секретной — она нужна только для повторения вычислений при проверке.
¶Проверка пароля
При аутентификации пользователя:
- Система извлекает соль, соответствующую данному пользователю.
- К введённому паролю добавляется та же соль.
- Вычисляется хеш.
- Полученный хеш сравнивается с сохранённым. Если они совпадают, пароль верен.
¶Криптографические свойства
¶Защита от радужных таблиц
Радужные таблицы — это предварительно вычисленные таблицы, которые сопоставляют хеши с исходными строками. Если соль уникальна для каждого пароля, злоумышленник не может использовать готовую таблицу: для каждого возможного пароля пришлось бы вычислять хеш для каждой возможной соли, что делает таблицу астрономически большой (размер таблицы растёт как произведение числа паролей на число солей).
¶Защита от атак по словарю
Даже если два пользователя имеют одинаковый пароль, их хеши будут разными из-за разных солей. Это предотвращает атаки, при которых злоумышленник, узнав хеш одного пользователя, может определить, что другой пользователь использует тот же пароль.
¶Устойчивость к коллизиям
Соль не влияет на устойчивость хеш-функции к коллизиям (ситуациям, когда два разных входа дают один и тот же хеш). Однако современные хеш-функции (например, SHA-256) обладают высокой устойчивостью к коллизиям, и соль не ухудшает это свойство.
¶Виды хеш-функций с солью
¶Адаптивные хеш-функции
Современные системы используют адаптивные (медленные) хеш-функции, которые специально спроектированы для защиты паролей. Они позволяют регулировать вычислительную сложность (количество итераций, объём памяти), что затрудняет перебор даже на мощном оборудовании.
- bcrypt: основана на шифре Blowfish. Позволяет задавать «стоимость» (cost factor) — количество итераций. Широко используется в веб-приложениях (например, в фреймворках Ruby on Rails, Django).
- scrypt: использует большой объём памяти (memory-hard), что делает атаки на GPU и ASIC менее эффективными. Применяется в криптовалютах (например, Litecoin) и некоторых системах аутентификации.
- Argon2: победитель конкурса Password Hashing Competition (2015). Поддерживает три варианта: Argon2d (устойчив к атакам по времени), Argon2i (защищён от side-channel атак), Argon2id (комбинированный). Рекомендуется как стандарт де-факто.
- PBKDF2: основана на многократном применении хеш-функции (например, SHA-256). Проста в реализации, но менее устойчива к атакам на GPU по сравнению с bcrypt и scrypt.
¶Простые хеш-функции с солью
В устаревших системах (например, Unix-пароли) использовались более простые алгоритмы:
- DES-крипт: 56-битный DES, 12-битная соль. Устарел из-за слабой стойкости.
- MD5-крипт: 128-битный MD5, 1000 итераций, 12-битная соль. Считается небезопасным.
- SHA-256-крипт / SHA-512-крипт: 256- или 512-битные хеши, до 5000 итераций, 16-символьная соль. Используются в Linux (модуль pam_unix).
¶Применение
¶Хранение паролей в веб-приложениях
Практически все современные веб-сервисы (социальные сети, банки, почтовые системы) используют хеширование с солью для хранения паролей. Например, в системе управления контентом WordPress пароли хранятся с использованием bcrypt, а в фреймворке Django — с использованием PBKDF2.
¶Базы данных и файловые системы
- SQL Server: использует алгоритм SHA-512 с солью для хранения паролей (начиная с SQL Server 2012).
- MySQL: функция
PASSWORD()в старых версиях использовала двойной SHA-1 без соли, что было признано небезопасным. В современных версиях рекомендуется использовать bcrypt или PBKDF2. - Linux: файл
/etc/shadowхранит хеши паролей с солью, используя алгоритмы SHA-512 или SHA-256.
¶Криптовалюты и блокчейн
В криптовалютах (например, Bitcoin) используется хеширование с солью для генерации адресов кошельков и защиты ключей. Однако в контексте майнинга соль не применяется — там используется простой хеш (SHA-256).
¶Защита от утечек
При утечке базы данных хеши с солью значительно затрудняют подбор паролей. Например, в 2012 году произошла утечка данных сервиса LinkedIn: пароли хранились в виде простого SHA-1 без соли, что позволило злоумышленникам быстро восстановить миллионы паролей. После этого инцидента LinkedIn перешёл на bcrypt.
¶Критика и ограничения
¶Необходимость уникальной соли
Если соль не является уникальной для каждого пароля (например, используется одна и та же соль для всех пользователей), защита от радужных таблиц теряется. Злоумышленник может построить таблицу для этой соли и подобрать все пароли за один раз.
¶Слабые хеш-функции
Использование устаревших хеш-функций (MD5, SHA-1) даже с солью не обеспечивает достаточной защиты, так как эти функции подвержены атакам на коллизии и могут быть вычислены очень быстро на современном оборудовании.
¶Атаки по времени
Если сравнение хешей выполняется неконстантным по времени способом (например, с ранним выходом при несовпадении первого байта), злоумышленник может провести атаку по времени, чтобы восстановить хеш байт за байтом. Современные реализации (например, в bcrypt) используют константное сравнение.
¶Проблемы с длиной соли
Слишком короткая соль (менее 8 байт) может быть подвержена атакам перебором: злоумышленник может построить радужные таблицы для всех возможных солей, если их количество невелико. Рекомендуемая длина соли — не менее 16 байт (128 бит).
¶Примеры реализации
¶На Python (с использованием bcrypt)
```python import bcrypt
¶Генерация соли и хеширование
password = b"my_secret_password" salt = bcrypt.gensalt() # генерирует случайную соль hashed = bcrypt.hashpw(password, salt)
¶Проверка пароля
if bcrypt.checkpw(password, hashed): print("Пароль верен") else: print("Пароль неверен") ```
¶На PHP (с использованием password_hash)
```php $password = "my_secret_password"; $hashed = password_hash($password, PASSWORD_BCRYPT); // автоматически генерирует соль
if (password_verify($password, $hashed)) { echo "Пароль верен"; } else { echo "Пароль неверен"; } ```
¶На Java (с использованием PBKDF2)
```java import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import java.security.SecureRandom; import java.util.Base64;
public class PasswordHashing { public static byte[] generateSalt() { SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); return salt; }
public static byte[] hashPassword(String password, byte[] salt) throws Exception { PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10000, 256); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); return factory.generateSecret(spec).getEncoded(); } } ```
¶Интересные факты
- В Unix-системах соль традиционно представляла собой 12-битное число (4096 возможных значений), что было достаточно для защиты от радужных таблиц в 1970-х годах, но сегодня считается слабым.
- Алгоритм bcrypt был разработан в 1999 году Нильсом Провосом и Дэвидом Мазьером и до сих пор считается одним из самых надёжных.
- В 2013 году компания Facebook (организация Meta признана экстремистской и запрещена в РФ) перешла на использование bcrypt для хранения паролей после утечки данных.
- Конкурс Password Hashing Competition (2013–2015) был организован для выбора нового стандарта хеширования паролей. Победителем стал Argon2, разработанный командой из Университета Люксембурга.
¶Источники
- Provos, N., & Mazières, D. (1999). A Future-Adaptable Password Scheme. Proceedings of the 1999 USENIX Annual Technical Conference.
- Percival, C. (2009). Stronger Key Derivation via Sequential Memory-Hard Functions. BSDCan 2009.
- Biryukov, A., Dinu, D., & Khovratovich, D. (2016). Argon2: New Generation of Memory-Hard Functions for Password Hashing and Other Applications. Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security.
- RFC 2898 — PKCS #5: Password-Based Cryptography Specification Version 2.0.
- OWASP Password Storage Cheat Sheet.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


