Що таке засолення паролів у безпеці? Пояснення хешування паролів
У червні 2012 року зловмисник виклав на російський форум 117 мільйонів записів облікових записів LinkedIn. Список являв собою стіну з несолоних хешів SHA-1. SHA-1 швидкий. Без солі для розшифровки однакових паролів той самий хеш знаходився поруч з тим самим хешем тисячі разів. Приблизно протягом сімдесяти двох годин дослідники з безпеки зламали близько дев'яноста відсотків файлу. Коли порушення знову виникло у травні 2016 року як частина набору даних зі 167 мільйонів записів, ці облікові дані роками використовувалися для кампаній з їх підробки.
Захист, який би пом’якшив це порушення до примітки — додавати сіль до кожного збереженого пароля — існував вже в 1979 році. Він називається «соленим засоленням». Він не новий, не дорогий і не особливо розумний. Це різниця між витоком бази даних як контрольованим інцидентом і тим, що він буде проблемою паролів для кожного протягом півдесятиліття.
Більшість сучасних збоїв у зберіганні паролів все ще виникають з тієї ж першопричини: хтось вирішив, що «ми використовуємо SHA-256» – це достатньо добре. У цій статті розглядається, що таке засолення насправді, як воно працює на практиці, від чого воно захищає, а від чого ні, і що OWASP рекомендує як стандартне налаштування у 2026 році.
Що таке сальтування в безпеці та хешуванні паролів
Скоротіть тему до одного речення. Соління означає додавання випадкових даних до пароля перед тим, як цей пароль буде хешовано. Випадкове значення — сіль — генерується один раз для кожного облікового запису, коли сіль генерується разом із новим хешем пароля, зберігається у відкритому вигляді поруч із результуючим хешем та зчитується під час кожного входу в систему. Це не ключ. Не секрет. Не шифрування. Публічний модифікатор з одним завданням: переконатися, що коли два користувачі мають однаковий пароль, вони ніколи не використовуватимуть один і той самий збережений хешований пароль.
Хешування саме по собі є одностороннім. Якщо проштовхнути пароль через SHA-256 або Argon2id, ви отримаєте значення фіксованої довжини, яке жоден алгоритм не може скасувати. Загвоздка в тому, що «жоден алгоритм» виключає один дешевий скорочений варіант — пошук хешу в попередньо обчисленому словнику. Соління закриває цей скорочений варіант. Додавання солі до процесу хешування створює унікальний хеш для кожного користувача, навіть якщо текст їхнього пароля дослівно ідентичний. Поширені паролі, такі як «password» та «qwerty», більше не конфліктують у базі даних. Соління гарантує, що витік одного рядка нічого не розповість зловмиснику про когось іншого.
Три правила відрізняють корисну сіль від некорисної. Перше правило: кожен пароль отримує свою власну випадкову сіль, щойно згенеровану, коли користувач реєструється або скидає налаштування. Пароль із сіллю, який використовується повторно в різних облікових записах, навряд чи кращий за несолоний пароль — масова атака працює так само. Друге правило: сіль може бути публічною. Знання самої солі не дає зловмиснику жодного скорочення доступу до базової хеш-функції. Таким чином, сіль знаходиться в базі даних поруч із хешем, і таке розміщення є прийнятним, навіть заохочується. Третє правило: значення солі надходять з криптографічно захищеного генератора псевдовипадкових чисел. Linux надає такий код через `getrandom(2)`. Node називає його `crypto.randomBytes`. Стандартна бібліотека Python огортає його в `secrets.token_bytes`. Некриптографічний `Math.random()` є непридатним, хоча він з'являється в реальному перевіреному коді набагато частіше, ніж мав би.
Двоє людей, які обирають пароль «hunter2», повинні мати два абсолютно різні збережені хеші. Це відбувається за допомогою солі. Якщо пропустити солі, база даних витікає не лише хеші, а й соціальний графік того, хто з ким ділиться яким паролем.
Як працює переробка паролів за допомогою солі
Механізм поділяється на чотири кроки, і десять років порушень сховища паролів показують, що майже кожен збій трапляється через те, що хтось пропустив один із них.
Перший крок виконується під час реєстрації. Додаток запитує у CSPRNG від шістнадцяти до тридцяти двох випадкових байтів. У цьому і полягає суть. Керівництво OWASP на 2025 рік трактує шістнадцять байтів (128 бітів) як мінімальне значення; auth0 та кілька постачальників менеджерів паролів рекомендують використовувати тридцять два. Стандарт NIST SP 800-63B-4 встановлює мінімум у чотири байти, але попереджає, що колізії, пов'язані з датою народження, починають з'являтися приблизно після шістдесяти п'яти тисяч користувачів такого розміру, тому ніхто насправді не використовує чотири байти.
Крок другий поєднує «саль» з обраним користувачем паролем. Конкатенація є найпоширенішою формою, при цьому «саль» розміщується перед або після рядка пароля. Деякі системи використовують HMAC, розглядаючи «саль» як ключ HMAC, що дозволяє обійти кілька незрозумілих проблем із розширенням довжини, що виникають при «сирій» конкатенації.
На третьому кроці об'єднані вхідні дані пропускаються через алгоритм хешування паролів — те, що в підручниках з криптографії називають функцією виведення ключа, або KDF. Саме на цьому кроці більшість команд раніше зазнавали невдачі, часто звертаючись до загального алгоритму хешування та вважаючи, що робота виконана. Звичайний SHA-256 сам по собі не підходить для зберігання паролів. Споживчий графічний процесор у 2026 році циклічно обробляє понад сто мільярдів хешів SHA-256 за секунду, тому навіть з використанням солі вартість кожного вгадування при криптографічному хешуванні залишається незначною. Соль знищує вектори атак на райдужні таблиці. Вона сама по собі не уповільнює злому паролів методом грубої сили. Правильним інструментом тут є навмисно повільна функція, яка потребує багато пам'яті: Argon2id — це функція за замовчуванням, яку бажає OWASP, з прийнятними scrypt та bcrypt, а PBKDF2 з дуже високою кількістю ітерацій дозволена там, де відповідність FIPS-140 вимагає цього вибору.
Крок четвертий зберігає як хеш, так і сіль. Сучасні бібліотеки обробляють формат зберігання, тому вам не потрібно керувати збереженою сіллю вручну. Вивід bcrypt виглядає так: `$2b$12$9f4c8a7b...kQR8YZpL9` — цей єдиний рядок містить ідентифікатор алгоритму, коефіцієнт вартості, сіль та хеш-значення. Argon2id використовує аналогічний формат рядка PHC, `$argon2id$v=19$m=19456,t=2,p=1$$`. Ви записуєте цей рядок у стовпець бази даних і йдете далі. Бібліотека зробила все необхідне для безпечного зберігання паролів — згенерувала випадкові дані для солі, пропустила пароль через повільний алгоритм хешування та об'єднала результат для отримання.
Вхід виконується за тим самим конвеєром у зворотному порядку. Додаток шукає сіль користувача та збережений хеш, пропускає надісланий пароль за тим самим алгоритмом з тією ж сіллю та порівнює результат зі збереженим хешем, використовуючи порівняння з константою часу. Константа часу має значення: наївний оператор `==` витікає інформацію про те, скільки байтів збігається, що призводить до реальних вразливостей, пов'язаних з атакою за часом. Використовуйте `hmac.compare_digest`, `crypto.timingSafeEqual` або еквівалент вашого фреймворку.

Чому важливо соління: проблема райдужного столу
Райдужні таблиці – це специфічна атака, для боротьби з якою було винайдено використання солі. Уявіть собі попередньо обчислену таблицю пошуку, яка зіставляє кожен правдоподібний пароль – кожне слово зі словника, поширений варіант, запис зі списку витоків – з його хешем SHA-256. Ці таблиці існують, вони продаються на форумах зі злому, і їх розмір сягає терабайтів. Щойно зловмисник отримує дамп бази даних несолоних хешів, пошук хешу в райдужній таблиці є запитом до бази даних, а не зломіною. LinkedIn 2012 пройшов саме так: 117 мільйонів несолоних SHA-1 хешів проти райдужної таблиці, дев'яносто відсотків зламаних приблизно за три дні.
Додайте сіль для кожного користувача, і райдужні таблиці перестануть працювати. Зловмиснику знадобиться окрема попередньо обчислена таблиця для кожного унікального значення солі. З шістнадцятибайтовою випадковою сіллю це означає 117 мільйонів різних таблиць для 117 мільйонів користувачів, і кожна таблиця все одно буде розміром у терабайти. Власне лише витрати на зберігання роблять це неможливим. Атака випадає з моделі загрози.
У цьому вся робота солі. Вона навмисно вузька. Солі не уповільнюють рішучу спробу грубої сили проти одного конкретного користувача. Солі не зупиняють підтасовування облікових даних після попереднього витоку. Солі не допомагають, якщо сам пароль — «123456» — зловмисник пробує очевидний словник, і солі перераховуються для кожного вгадування, але не змінюють суттєво вартість кожного вгадування.
Що надійно зменшує використання солі: райдужних таблиць та витоку інформації про повторне використання паролів між користувачами в одній базі даних. Що зменшує повільне хешування: вартості кожного вгадування. Що зменшує перець: крадіжка лише з бази даних. Що зменшує MFA: заповнення облікових даних. Соління – це один рівень безпеки в стеку — додавання солі для складнішого злому паролів не те саме, що зробити кожен пароль окремо важким для вгадування. Метою, якої досягає солі, є різний хеш для кожного користувача; збільшення витрат на кожне вгадування – це окрема проблема.
Хешування проти шифрування проти засолення
Три терміни, які плутають, особливо в статтях неспеціалістів. Вони не є взаємозамінними.
| Шифрування | Хешування | Соління | |
|---|---|---|---|
| Оборотний | Так, з ключем | Ні, за задумом | Модифікатор, не автономний |
| Довжина виходу | Змінна, відповідає введеним даним | Фіксований (зазвичай 256 біт) | Н/Д — змінює введений хеш |
| Використовується для | Конфіденційність даних | Цілісність, зберігання паролів | Посилення хешів |
| Потрібен ключ | Так, секрет | Ні | Ні, використовується випадкова сіль |
Шифрування захищає дані, які ви хочете отримати пізніше. Отримувач зберігає ключ, застосовує його та зчитує оригінал. Хешування є одностороннім: як тільки пароль стає хешем, жоден алгоритм не змінює його значення. Соління – це модифікатор, який ви застосовуєте до вхідних даних хеш-функції — воно не має значення саме по собі.
Витік даних Adobe у 2013 році є показовим прикладом. Adobe зберігала 153 мільйони записів користувачів, шифруючи паролі за допомогою 3DES у режимі ECB під одним ключем на рівні сайту. Цей вибір зазнав потрійної невдачі. Шифрування — неправильний примітив для зберігання паролів. Режим ECB витікає як ідентичні вхідні, так і вихідні дані. Повторне використання одного ключа по всій базі даних означало, що декодування ключа після декодування всіх 153 мільйонів записів. Шнайєр назвав це одним із найгірших витоків паролів в історії. Виправленням на кожному рівні було перехід на повільне хешування з використанням солоних речовин.
Сіль проти перцю: двошаровий захист
Перець (Pepper) – менш відомий двоюрідний брат солі (salt). Концепція: додаткове секретне значення, що застосовується до кожного пароля, який обробляє програма, але зберігається поза базою даних. Змінна середовища, запис служби керування ключами або резидентний ключ HSM. Сіль знаходиться поруч із хешем у відкритому тексті. Перець – ні.
Модель загрози полягає в крадіжці лише бази даних. Якщо зловмисник краде лише базу даних — через SQL-ін'єкцію, неправильно налаштовану резервну копію або витік дампа — у нього є солі та хеші, але немає перцю. Без перцю вони навіть не можуть розпочати перебір, оскільки в кожному припущенні, яке вони хешують, відсутній модифікатор глобального секрету.
Типова реалізація виконує `argon2id(salt + password + pepper)` або, більш ретельно, спочатку обчислює `HMAC(pepper, password + salt)` і передає результат в Argon2id. OWASP рекомендує використовувати pepper для систем з високою вартістю, але визнає компроміс: ротація pepper є операційно складною. Її ротація означає повторне використання пароля кожного користувача під час наступного входу в систему, і якщо pepper коли-небудь буде втрачено без резервної копії, кожен обліковий запис стане неперевіреним. Більшість споживчих програм пропускають pepper. Банки, урядові установи та системи охорони здоров'я зазвичай цього не роблять.
Сучасне хешування паролів у 2026 році
У рекомендаціях OWASP щодо зберігання паролів за 2025 рік чотири алгоритми ранжуються в порядку пріоритетності. Salt вбудований у всі з них — ви не генеруєте його вручну.
| Алгоритм | Мінімум OWASP 2025 | Специфікація |
|---|---|---|
| Argon2id (бажано) | m=19 МіБ, t=2, p=1 | РФК 9106 (2021) |
| крипта | N=2^17, r=8, p=1 | РФК 7914 (2016) |
| bcrypt (застарілий) | вартість ≥ 10; обмеження вхідних даних 72 байти | Нільс Провос, 1999 |
| PBKDF2-HMAC-SHA256 | 600 000 ітерацій | RFC 2898; лише FIPS |
Argon2id ресурсомісткий до пам'яті, тобто кожна здогадка потребує не лише циклів процесора, але й певного фрагмента оперативної пам'яті. Мінімум 19 МіБ на хеш, встановлений OWASP, означає, що зловмисник, який створює власний ASIC, також повинен створити багато швидкої пам'яті, а пам'ять є дорогою частиною будь-якої системи. Варіант "id" поєднує Argon2i (стійкий до бічних каналів) та Argon2d (стійкий до графічного процесора), запускаючи Argon2i протягом першої половини, а Argon2d — протягом другої.
scrypt передує Argon2id і працює за тим самим принципом жорсткого використання пам'яті. bcrypt ще старший, простіший і має жорстке обмеження вхідних даних у 72 байти, яке іноді зупиняє роботу програм, що використовують довгі парольні фрази — попереднє хешування за допомогою SHA-256 та base64-encode, якщо вам потрібні довші вхідні дані. PBKDF2 — це повільний, але сумісний з FIPS варіант; OWASP збільшив кількість ітерацій до 600 000 для SHA-256 у 2023 році, порівняно з 310 000.
Чого не входить до цього списку: звичайний SHA-256, звичайний SHA-512, MD5, SHA-1 та будь-яка користувацька функція, що закінчується на "+ salt". Швидкість — це вирішальний фактор. SHA-256 був розроблений для швидкої роботи на звичайному обладнанні. Це протилежно тому, що потрібно для зберігання паролів.
Поширені помилки під час засолення, які проявляються під час реальних аудитів
У звітах про порушення безпеки з реального світу постійно фіксується одна й та сама ж жменька помилок.
Повторне використання однієї солі для кожного користувача руйнує весь механізм — проблема райдужної таблиці повертається, тільки з одним додатковим кроком. Використання імені користувача як солі гірше, оскільки імена користувачів повторюються в різних системах, а райдужні таблиці можна попередньо обчислити для популярних. Довжина солі менше шістнадцяти байт починає допускати колізії в масштабі великих баз користувачів. Генерація солі за допомогою некриптографічної випадкової функції — `Math.random()`, `time(0)` mod something, генератора випадкових чисел за замовчуванням мови — створює передбачувані значення, які позбавляють солі її переваг.
Більш тонка помилка — це зберігання солі на іншому сервері «для безпеки». Сіль не є секретом. Розділення її між системами збільшує операційну складність, не додаючи криптографічної стійкості. Зберігайте її в тому ж рядку, що й хеш. Сучасні рядки PHC роблять це за вас.
Найбільшим недоліком, який відбувся в аудитах 2026 року, є хешування за допомогою простого SHA-256 плюс саль та доставка. Саль запобігає появі райдужних таблиць. Вона нічого не робить з фермою GPU, яка виконує десять мільярдів припущень на секунду для одного облікового запису. Виправлення полягає не в додаванні другої солі; це перехід на повільний KDF, такий як Argon2id.
Останнє: застарілі несолоні хеші. Міграція не є необов'язковою. Стандартний шаблон полягає в перевірці застарілого хешу під час наступного входу, повторному хешуванні за допомогою сучасного алгоритму та перезаписі. Для користувачів, які більше ніколи не входять у систему, примусово скидайте пароль у встановлені терміни.

Чому лише засолювання недостатньо
Соління — це шар, а не фортеця. Воно перемагає одну конкретну атаку — попередньо обчислені таблиці — і нічого не розкриває про надійність базового пароля. Груба сила все ще працює проти слабких паролів. Заповнення облікових даних все ще працює проти повторно використаних паролів. Фішинг все ще працює проти будь-якого пароля.
Справжня безпека паролів у 2026 році поєднує чотири захисні механізми. Argon2id з шістнадцятибайтовою соллю для кожного користувача керує сховищем. Функція «pepper», необов'язкова, але корисна для чутливих систем, блокує лише крадіжку бази даних. Багатофакторна автентифікація блокує фальсифікацію облікових даних та більшість видів фішингу. Постійний моніторинг порушень — такі сервіси, як Have I Been Pwned та його API — фіксують момент, коли облікові дані користувача з'являються під час витоку, щоб його можна було змусити скинути налаштування.
Пропустивши будь-який із цих шарів, зловмисник зрештою знайде прогалину. Одне лише застосування солі або будь-який окремий захист – це саме те, що кожен аналіз порушення за останнє десятиліття визначив як точку провалу.