Hashowanie haseł w bazie danych

1

Hej,

Korzystam z BcryptPasswordEncoder, dzięki czemu moje hasła przechowywane w bazie danych są ciągiem niezrozumiałych znaków, zakodowanych jednostronnie. Zastanawia mnie natomiast, jak w takim razie wykonując logowanie, spring weryfikuje czy podane hasło przez użytkownika zgadza się z tym podanym w bazie danych? Na jakiej zasadzie jest to porównywane?

1

Podane przy logowaniu hasło jest hashowane tą samą funkcją i hashe są porównywane, hashowanie daje taki sam skrót, dla takich samych danych.

6

W bazie trzymasz hash i salt (po co salt będzie opisane później). Hash powstaje z podanego przez użytkownika hasła z doklejonym saltem i to zapisujesz w bazie danych. Salt to wygenerowany losowy ciąg kilku znaków, który też zostaje zapisany w bazie danych.
Gdy użytkownik loguje się i wysyła hasło, z bazy danych na podstawie loginu wyciągany jest hash i salt, następnie tak jak wyżej - do przysłanego hasła doklejany jest salt z bazy i obliczany jest hash tego ciągu i hash ten jest porównywany z tym z bazy danych. Jeśli oba hashe są takie same, to z dużym prawdopodobieństwem podane przez użytkownika hasło jest prawidłowe.

Jeśli hasło jest nieprawidłowe, a mimo to hash jest taki sam, to mowa o kolizji. Tak działa metoda brute-force, generujesz hashe mniej lub bardziej losowych ciągów znaków aż znajdziesz kolizję. Wymaga to jednak olbrzymiej ilości obliczeń, tym więcej im dłuższy hash i/lub bardziej skomplikowany obliczeniowo algorytm.
Jest jeszcze druga metoda włamania - rainbow tables, czyli miliony/miliardy wygenerowanych hashy wraz ze źródłowymi danymi (słowami/hasłami), całość zapisana w łatwej do przeszukiwania postaci. Jeśli masz dostęp do tabelki z danymi użytkowników, to możesz próbować dopasować hashe ich haseł do danych z rainbow table i raz-dwa-trzy dla w miarę typowych haseł masz znalezione kolizje. Piszę "kolizje", a nie hasła, bo nie ma pewności, że to są oryginalne hasła użytkowników, ale nie ma to znaczenia. Jednak da się przed tym zabezpieczyć: trzeba tylko zrobić tak, żeby hasło nie było "typowe" :-) Da się to zrobić nie zmuszając do wysiłku użytkownika: otóż wystarczy do hasła dokleić losowy ciąg znaków (salt) i tenże ciąg gdzieś zapisać. Najbezpieczniej jest zrobić salt unikalny per użytkownik, wtedy niemożliwe jest wygenerowanie od nowa rainbow table pod konkretny salt, ale nawet użycie jednego salta dla wszystkich bardzo mocno utrudni odszukanie kolizji.

Skąd się biorą kolizje? Długość hasha jest skończona, ale długość hashowanych danych nie ma ograniczeń. Dla ustalenia uwagi: MD5 to 128b, zatem dla każdych danych dłuższych od 128b muszą istnieć inne dane dające taki sam wynik (zresztą za sprawą specyfiki algorytmu dla krótszych też mogą być kolizje). Im danych wejściowych jest więcej, tym więcej jest kolizji. Inną sprawą jest jej znalezienie - p-wo znalezienia kolizji każdej losowej próby wynosi 2^-128 (circa 3*10^-39).

Hash dla tych samych danych wejściowych zawsze daje te same dane wyjściowe. Korzystają z tego zabezpieczenia umożliwiające weryfikację integralności kodu (np. pliki .md5 dostępne do ściągnięcia obok pliku .exe). Mogą też korzystać z certyfikatów, które używają algorytmów szyfrowania asymetrycznego (klucz prywatny/publiczny), ale nie będę się rozpisywać, bo wątek jest o hashach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1