Czym jest salting w zabezpieczeniach? Wyjaśnienie haszowania haseł

Czym jest salting w zabezpieczeniach? Wyjaśnienie haszowania haseł

W czerwcu 2012 roku atakujący wrzucił 117 milionów rekordów kont LinkedIn na rosyjskie forum. Lista była ścianą niezasolonych haszy SHA-1. SHA-1 jest szybki. Bez soli do łamania identycznych haseł, ten sam hasz występował obok tego samego hasza tysiące razy. W ciągu około siedemdziesięciu dwóch godzin badacze bezpieczeństwa złamali około dziewięćdziesięciu procent pliku. Kiedy włamanie nastąpiło ponownie w maju 2016 roku, w ramach zbioru danych obejmującego 167 milionów rekordów, dane uwierzytelniające te przez lata zasilały kampanie wykorzystujące tzw. „crederstuffing”.

Obrona, która złagodziłaby to naruszenie i ograniczyła się do przypisu – polegająca na dodawaniu soli do każdego przechowywanego hasła – istniała już w 1979 roku. Nazywa się to „soleniem”. Nie jest to nic nowego, ani kosztowne, ani szczególnie sprytne. To różnica między wyciekiem bazy danych, który był incydentem kontrolowanym, a problemem haseł dla wszystkich przez pół dekady.

Większość współczesnych błędów w przechowywaniu haseł wciąż ma tę samą przyczynę: ktoś uznał, że „używamy SHA-256” jest wystarczająco dobre. W tym artykule omówiono, czym właściwie jest salting, jak działa w praktyce, przed czym chroni, a przed czym nie, oraz co OWASP zaleca jako domyślną metodę w 2026 roku.

Czym jest solenie w zabezpieczeniach i haszowaniu haseł?

Skróć temat do jednego zdania. Salting oznacza dodawanie losowych danych do hasła przed jego zahaszowaniem. Losowa wartość — salt — jest generowana raz dla każdego konta, gdy salt jest generowany wraz z nowym hashem hasła, przechowywana w postaci jawnej obok wynikowego hasha i odczytywana przy każdym logowaniu. To nie jest klucz. Nie jest to sekret. Nie jest to szyfrowanie. To publiczny modyfikator z dokładnie jednym zadaniem: upewnieniem się, że dwaj użytkownicy z tym samym hasłem nigdy nie będą mieli tego samego zapisanego hasha.

Samo haszowanie jest jednokierunkowe. Przepuszczenie hasła przez SHA-256 lub Argon2id powoduje otrzymanie wartości o stałej długości, której żaden algorytm nie jest w stanie odwrócić. Problem polega na tym, że „brak algorytmu” wyklucza jeden tani skrót – wyszukiwanie skrótu w wstępnie obliczonym słowniku. Dodanie soli do procesu haszowania powoduje zamknięcie tego skrótu. Dodanie soli do procesu haszowania tworzy unikalny skrót dla każdego użytkownika, nawet jeśli tekst ich hasła bazowego jest identyczny słowo w słowo. Popularne hasła, takie jak „password” i „qwerty”, nie kolidują już w bazie danych. Dodanie soli gwarantuje, że wyciek jednego wiersza nie powie atakującemu nic o innych użytkownikach.

Trzy zasady odróżniają użyteczną sól od bezużytecznej. Pierwsza zasada: każde hasło otrzymuje własną losową sól, generowaną na nowo podczas rejestracji lub resetowania hasła. Hasło z solą, używane wielokrotnie na różnych kontach, niewiele różni się od hasła bez soli — atak zbiorczy działa w ten sam sposób. Druga zasada: sól może być publiczna. Sama znajomość soli nie daje atakującemu żadnej możliwości uniknięcia użycia funkcji skrótu. Zatem sól znajduje się w bazie danych obok skrótu, a takie umiejscowienie jest w porządku, a nawet zalecane. Trzecia zasada: wartości soli pochodzą z kryptograficznie bezpiecznego generatora liczb pseudolosowych. Linux udostępnia go poprzez `getrandom(2)`. Node nazywa go `crypto.randomBytes`. Standardowa biblioteka Pythona opakowuje go w `secrets.token_bytes`. Niekryptograficzne `Math.random()` jest nieodpowiednie, mimo że pojawia się w rzeczywistym, audytowanym kodzie znacznie częściej niż powinno.

Dwie osoby wybierające hasło „hunter2” powinny uzyskać dwa zupełnie różne zapisane hasze. Właśnie to umożliwia solenie. Pomiń solenie, a baza danych wycieknie nie tylko z haszy, ale także z wykresu społecznościowego, który pokazuje, kto z kim dzieli dane hasło.

Jak działa solenie haseł

Mechanizm ten składa się z czterech kroków, a dziesięć lat naruszeń bezpieczeństwa haseł pokazuje, że niemal każdy błąd wynika z tego, że ktoś pominął jeden z kroków.

Krok pierwszy uruchamia się w momencie rejestracji. Aplikacja prosi generator CSPRNG o szesnaście do trzydziestu dwóch losowych bajtów. To jest sól. Wytyczne OWASP na rok 2025 traktują szesnaście bajtów (128 bitów) jako dolną granicę; auth0 i kilku dostawców menedżerów haseł zalecają przejście na trzydzieści dwa. Norma NIST SP 800-63B-4 określa minimum cztery bajty, ale ostrzega, że kolizje związane z urodzinami zaczynają pojawiać się u około sześćdziesięciu pięciu tysięcy użytkowników o takiej wielkości, dlatego nikt tak naprawdę nie używa czterech bajtów.

Krok drugi łączy sól z wybranym przez użytkownika hasłem. Konkatenacja to najpopularniejsza forma, w której sól umieszczana jest przed lub po ciągu hasła. Niektóre systemy używają HMAC, traktując sól jako klucz HMAC, co pozwala ominąć kilka niejasnych problemów z rozszerzeniem długości w przypadku surowej konkatenacji.

Krok trzeci przepuszcza połączone dane wejściowe przez algorytm haszujący hasła — który podręczniki kryptografii nazywają funkcją wyprowadzania klucza, czyli KDF. To właśnie na tym etapie większość zespołów zawodziła, często sięgając po ogólny algorytm haszujący i uznając zadanie za wykonane. Zwykły algorytm SHA-256 nie nadaje się do samodzielnego przechowywania haseł. Konsumencki procesor graficzny w 2026 roku przetwarza ponad sto miliardów haszy SHA-256 na sekundę, więc nawet z solą koszt pojedynczego odgadnięcia w haszowaniu kryptograficznym pozostaje znikomy. Solenie eliminuje wektory ataków typu rainbow table. Samo w sobie nie spowalnia łamania haseł metodą brute force. Właściwym narzędziem jest tutaj celowo powolna, wymagająca dużej pamięci funkcja: Argon2id jest preferowanym domyślnym algorytmem OWASP, z akceptowalnymi funkcjami scrypt i bcrypt, a PBKDF2 z bardzo dużą liczbą iteracji jest dozwolony tam, gdzie zgodność ze standardem FIPS-140 wymusza wybór.

Krok czwarty przechowuje zarówno skrót, jak i sól. Nowoczesne biblioteki obsługują format przechowywania, dzięki czemu nie trzeba ręcznie zarządzać przechowywaną solą. Wynik bcrypt wygląda następująco: `$2b$12$9f4c8a7b...kQR8YZpL9` — ten pojedynczy ciąg znaków zawiera identyfikator algorytmu, współczynnik kosztu, sól i wartość skrótu. Argon2id używa analogicznego formatu ciągu znaków PHC: `$argon2id$v=19$m=19456,t=2,p=1$$`. Zapisujesz ten ciąg znaków do kolumny bazy danych i odchodzisz. Biblioteka zrobiła wszystko, co potrzebne do bezpiecznego przechowywania haseł — wygenerowała losowe dane dla soli, przepuściła hasło przez powolny algorytm skrótu i spakowała wynik do pobrania.

Logowanie odbywa się w odwrotnej kolejności. Aplikacja wyszukuje sól użytkownika i zapisany hash, przepuszcza przesłane hasło przez ten sam algorytm z tą samą solą i porównuje wynik z zapisanym hashem, używając porównania w czasie stałym. Czas stały ma znaczenie: naiwny `==` ujawnia informacje o liczbie dopasowanych bajtów, co prowadzi do rzeczywistych luk w zabezpieczeniach związanych z atakiem czasowym. Użyj `hmac.compare_digest`, `crypto.timingSafeEqual` lub odpowiednika w Twojej platformie.

Solenie w bezpieczeństwie

Dlaczego solenie jest ważne: problem stołu tęczowego

Tabele tęczowe to konkretny atak, do którego pokonania wymyślono metodę saltingu. Wyobraź sobie wstępnie obliczoną tablicę wyszukiwania, która mapuje każde prawdopodobne hasło – każde słowo ze słownika, popularną odmianę, wpis z listy wycieków – na jego skrót SHA-256. Takie tablice istnieją, są sprzedawane na forach crackerskich i zajmują terabajty. Gdy atakujący zdobędzie zrzut bazy danych niezasolonych skrótów, wyszukanie skrótu w tablicy tęczowej to zapytanie do bazy danych, a nie zadanie crackingu. LinkedIn 2012 postąpił dokładnie tak: 117 milionów niezasolonych skrótów SHA-1 dla tablicy tęczowej, 90% złamanych w około trzy dni.

Dodanie soli dla każdego użytkownika i tabele tęczowe przestaną działać. Atakujący potrzebowałby osobnej, wstępnie obliczonej tabeli dla każdej unikalnej wartości soli. Przy szesnastobajtowej losowej soli oznacza to 117 milionów różnych tabel dla 117 milionów użytkowników — a każda tabela i tak miałaby rozmiar terabajtów. Same koszty pamięci masowej sprawiają, że jest to niewykonalne. Atak wypada z modelu zagrożenia.

Na tym właśnie polega działanie soli. Celowo jest ona zawężona. Solenie nie spowalnia zdeterminowanej próby siłowej skierowanej przeciwko konkretnemu użytkownikowi. Solenie nie zapobiega też fałszowaniu danych uwierzytelniających z poprzedniego wycieku. Solenie nie pomaga, jeśli samo hasło to „123456” — atakujący próbuje użyć oczywistego słownika, a sól jest przeliczana dla każdego odgadnięcia, ale nie zmienia znacząco kosztu odgadnięcia.

Co skutecznie łagodzi solenie: tabele tęczowe i wyciek informacji o ponownym użyciu haseł między użytkownikami w tej samej bazie danych. Co łagodzi powolne haszowanie: koszt próby odgadnięcia. Co łagodzi pepper: kradzież danych tylko w bazie danych. Co łagodzi MFA: upychanie danych uwierzytelniających. Solenie to jedna z warstw zabezpieczeń w stosie — dodanie soli w celu utrudnienia łamania haseł nie jest tym samym, co utrudnienie odgadnięcia każdego hasła z osobna. Celem solinia jest uzyskanie innego hasha dla każdego użytkownika; uczynienie każdego odgadnięcia kosztownym to osobny problem.

Haszowanie kontra szyfrowanie kontra solenie

Trzy terminy, które bywają mylone, zwłaszcza w opracowaniach osób niebędących specjalistami. Nie można ich stosować zamiennie.

Szyfrowanie Haszowanie Solenie
Odwracalny Tak, z kluczem Nie, celowo Modyfikator, nie samodzielny
Długość wyjściowa Zmienna, pasuje do danych wejściowych Stały (zwykle 256 bitów) N/A — zmienia dane wejściowe hasha
Używany do Poufność danych Integralność, przechowywanie haseł Wzmacnianie haszy
Wymagany klucz Tak, sekret NIE Nie, używa losowej soli

Szyfrowanie chroni dane, które chcesz odzyskać później. Odbiorca przechowuje klucz, stosuje go i odczytuje oryginał. Haszowanie jest jednokierunkowe: gdy hasło stanie się haszem, żaden algorytm go nie odwróci. Salting to modyfikator stosowany do danych wejściowych funkcji haszującej — sam w sobie nie ma znaczenia.

Wyciek danych firmy Adobe z 2013 roku jest tu przestrogą. Firma Adobe przechowywała 153 miliony rekordów użytkowników, szyfrując hasła algorytmem 3DES w trybie ECB, używając jednego klucza dla całej witryny. Ten wybór okazał się potrójną porażką. Szyfrowanie to nieodpowiedni prymityw do przechowywania haseł. Tryb ECB powoduje wyciek identycznych danych wejściowych i wyjściowych. Ponowne użycie jednego klucza w całej bazie danych oznaczało, że jednokrotne odkodowanie klucza umożliwiało odkodowanie wszystkich 153 milionów rekordów. Schneier nazwał to jednym z najgorszych włamań do haseł w historii. Rozwiązaniem na każdym poziomie było przejście na powolne haszowanie z użyciem soli.

Sól kontra pieprz: dwuwarstwowa obrona

Pepper to mniej znany kuzyn Salta. Koncepcja: dodatkowa tajna wartość, stosowana do każdego hasła przetwarzanego przez aplikację, ale przechowywana poza bazą danych. Zmienna środowiskowa, wpis usługi zarządzania kluczami lub klucz rezydentny HSM. Salt znajduje się obok hasha w postaci jawnej. Pepper nie.

Model zagrożenia to kradzież samej bazy danych. Jeśli atakujący ukradnie tylko bazę danych – poprzez wstrzyknięcie kodu SQL, błędnie skonfigurowaną kopię zapasową lub wyciek zrzutu – będzie miał sole i skróty, ale nie będzie miał klucza. Bez klucza nie będzie mógł nawet rozpocząć ataku siłowego, ponieważ w każdym zgadywanym skrócie brakuje globalnego modyfikatora klucza.

Typowa implementacja uruchamia `argon2id(salt + password + pepper)` lub, bardziej precyzyjnie, najpierw oblicza `HMAC(pepper, password + salt)` i przekazuje wynik do Argon2id. OWASP zaleca stosowanie peppera w systemach o wysokiej wartości, ale uznaje kompromis: rotacja peppera jest uciążliwa pod względem operacyjnym. Rotacja oznacza ponowne hashowanie hasła każdego użytkownika przy następnym logowaniu, a jeśli pepper zostanie utracony bez kopii zapasowej, każde konto staje się niedostępne do sprawdzenia. Większość aplikacji konsumenckich pomija peppera. Banki, instytucje rządowe i służby zdrowia zazwyczaj tego nie robią.

Nowoczesne hashowanie haseł w 2026 r.

Wytyczne OWASP z 2025 roku dotyczące przechowywania haseł klasyfikują cztery algorytmy w kolejności preferencji. Sól jest wbudowana we wszystkie z nich — nie generuje się jej ręcznie.

Algorytm Minimalne wymagania OWASP 2025 Spec
Argon2id (preferowany) m=19 MiB, t=2, p=1 RFC 9106 (2021)
skrypt N=2^17, r=8, p=1 RFC 7914 (2016)
bcrypt (starsza wersja) koszt ≥ 10; limit wejściowy 72 bajtów Niels Provos, 1999
PBKDF2-HMAC-SHA256 600 000 iteracji RFC 2898; tylko FIPS

Argon2id jest pamięciochłonny, co oznacza, że każde odgadnięcie zajmuje nie tylko cykle procesora, ale także określony blok pamięci RAM. Minimalna wartość OWASP wynosząca 19 MiB na hash oznacza, że atakujący tworzący niestandardowy układ ASIC musi również zbudować dużo szybkiej pamięci, a pamięć jest kosztownym elementem każdej platformy. Wariant „id” łączy Argon2i (odporny na kanał boczny) i Argon2d (odporny na GPU), uruchamiając Argon2i w pierwszej połowie, a Argon2d w drugiej.

Scrypt jest starszy od Argon2id i działa na tej samej zasadzie pamięciochłonności. bcrypt jest jeszcze starszy, prostszy i ma sztywny limit 72 bajtów danych wejściowych, który czasami utrudnia działanie aplikacji korzystających z długich haseł — prehash z SHA-256 i kodowaniem base64, jeśli potrzebujesz dłuższych danych wejściowych. PBKDF2 to wolniejszy, ale zgodny ze standardem FIPS wybór; OWASP zwiększył liczbę iteracji SHA-256 do 600 000 w 2023 roku, w porównaniu z 310 000.

Czego nie ma na tej liście: zwykłego algorytmu SHA-256, zwykłego algorytmu SHA-512, MD5, SHA-1 i wszelkich funkcji niestandardowych kończących się na „+ salt”. Szybkość jest wadą. SHA-256 został zaprojektowany z myślą o szybkości na sprzęcie powszechnego użytku. To jest przeciwieństwo tego, czego potrzebuje przechowywanie haseł.

Typowe błędy w soleniu, które ujawniają się podczas rzeczywistych audytów

Raporty o naruszeniach bezpieczeństwa w świecie rzeczywistym wciąż wskazują na te same błędy.

Ponowne użycie jednej soli dla każdego użytkownika niweczy cały mechanizm — problem z tablicą tęczową powraca, ale wymaga tylko jednego dodatkowego kroku. Użycie nazwy użytkownika jako soli jest jeszcze gorsze, ponieważ nazwy użytkowników powtarzają się w różnych systemach, a tablice tęczowe można wstępnie obliczyć dla popularnych tablic. Długość soli poniżej szesnastu bajtów zaczyna dopuszczać kolizje w skali dużych baz użytkowników. Generowanie soli za pomocą niekryptograficznej funkcji losowej — `Math.random()`, `time(0)` modyfikuj coś, domyślny generator liczb losowych języka — generuje przewidywalne wartości, które pozbawiają funkcję soli jej zalet.

Subtelniejszym błędem jest przechowywanie soli na innym serwerze „ze względów bezpieczeństwa”. Sól nie jest tajemnicą. Podzielenie jej między systemy zwiększa złożoność operacyjną bez zwiększania siły kryptograficznej. Przechowuj ją w tym samym wierszu co hash. Nowoczesne ciągi PHC robią to za Ciebie.

Największym problemem, w audytach z 2026 roku, jest haszowanie zwykłym algorytmem SHA-256 z dodatkiem soli i wysyłką. Sól zapobiega tworzeniu tabel tęczowych. Nie robi nic w przypadku farmy GPU wykonującej dziesięć miliardów prób na sekundę na jednym koncie. Rozwiązaniem nie jest dodanie drugiej soli, ale przejście na powolny KDF, taki jak Argon2id.

Na koniec: starsze, niesolone hasze. Migracja nie jest opcjonalna. Standardowo weryfikacja starszego hasha odbywa się przy następnym logowaniu, ponowne haszowanie nowoczesnym algorytmem i nadpisanie. W przypadku użytkowników, którzy nigdy więcej się nie logują, należy wymusić resetowanie hasła w ustalonym czasie.

Solenie w bezpieczeństwie

Dlaczego samo solenie nie wystarczy

Salting to warstwa, a nie forteca. Udaremnia jeden konkretny atak – wstępnie obliczone tabele – i nie ujawnia nic na temat siły hasła bazowego. Ataki brute force nadal działają na słabe hasła. Wypychanie danych uwierzytelniających nadal działa na hasła wielokrotnie używane. Phishing nadal działa na każde hasło.

Prawdziwe bezpieczeństwo haseł w 2026 roku obejmuje cztery mechanizmy zabezpieczeń. Argon2id z szesnastobajtową solą dla każdego użytkownika obsługuje przechowywanie. Pepper, opcjonalny, ale przydatny w przypadku wrażliwych systemów, blokuje kradzież danych tylko do bazy danych. Uwierzytelnianie wieloskładnikowe blokuje upychanie danych uwierzytelniających i większość ataków phishingowych. Ciągły monitoring naruszeń — usługi takie jak Have I Been Pwned i jego API — wychwytują moment, w którym dane uwierzytelniające użytkownika zostaną ujawnione w wyniku wycieku, co pozwala na wymuszenie jego zresetowania.

Pominięcie którejkolwiek z tych warstw, a atakujący w końcu znajdzie lukę. Samo salting, czy jakakolwiek inna obrona, to właśnie to, co każda analiza po włamaniu w ostatniej dekadzie wskazywała jako punkt krytyczny.

Jakieś pytania?

Nie. Nazwy użytkowników powtarzają się w różnych usługach, atakujący wstępnie obliczają tablice tęczowe dla popularnych, a przewidywalne sole zapadają się z powrotem w problem z tablicami tęczowymi, który solenie ma wyeliminować. Zawsze pobieraj bajty z CSPRNG: `secrets.token_bytes(16)` w Pythonie, `crypto.randomBytes(16)` w Node.

Wytyczne OWASP na rok 2025 określają limit na szesnaście bajtów — 128 bitów. NIST technicznie dopuszcza sole czterobajtowe, ale kolizje związane z datą urodzin występują u około sześćdziesięciu pięciu tysięcy użytkowników o takim rozmiarze. Przy szesnastobajtowych solach prawdopodobieństwo kolizji wynosi około jeden do 2^64. W praktyce: nigdy.

Tak, przed wyszukiwaniem w tabelach tęczowych i wyciekiem danych o ponownym użyciu haseł między użytkownikami. Nie, przed cierpliwym atakiem bruteforce na jedno konkretne konto. Prawdziwa ochrona wymaga zasolenia w połączeniu z wolnym, wymagającym dużej pamięci hashem, takim jak Argon2id, a najlepiej z nałożoną na to wieloskładnikową metodą uwierzytelniania (MFA).

Sól to losowa wartość dodawana do hasła tuż przed haszowaniem – sztuczka, która sprawia, że każdy zapisany hash jest unikalny, nawet w przypadku haseł współdzielonych. Nie jest to sekret. Nie jest to klucz. Nie jest to szyfrowanie. Jest on przechowywany w haśle i jest generowany ponownie dla każdego nowego konta.

Wskazówka dotycząca hasła, a nie zasada „solenia”. Nakazuje użytkownikom połączenie trzech niepowiązanych ze sobą słów („trąbka-lodowiec-aksamit”) w celu uzyskania pamięci i entropii. Zasada „solenia” dotyczy sposobu, w jaki baza danych przechowuje wybrane hasło. Zasada trzech słów dotyczy wyboru hasła w pierwszej kolejności. Obie warstwy pomagają.

Salting polega na dodaniu unikalnej, losowej wartości do hasła przed jego zahaszowaniem. Chodzi o to, że dwóch użytkowników z dokładnie tym samym hasłem otrzymuje dwa różne zapisane hasze. Salt jest przypisany do konkretnego konta, publiczny i znajduje się w bazie danych tuż obok hasza. Jego prawdziwym zadaniem jest niszczenie tabel tęczowych.

Ready to Get Started?

Create an account and start accepting payments – no contracts or KYC required. Or, contact us to design a custom package for your business.

Make first step

Always know what you pay

Integrated per-transaction pricing with no hidden fees

Start your integration

Set up Plisio swiftly in just 10 minutes.