Hashowanie haseł w bazie danych

Hashowanie haseł w bazie danych
JA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około rok
  • Postów:46
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?

Zobacz pozostałe 3 komentarze
Ktos
Nie, bcrypt i inne funkcje haszujące są deterministyczne - dla takiego samego wejścia zawsze będzie takie samo wyjście. Inaczej to nie miało by sensu.
Patryk27
Ależ oczywiście, że są deterministyczne - przy czym wykorzystują dynamicznie generowaną sól, więc z punktu widzenia użytkownika / programisty uruchomienie dwukrotnie brypt("hello world") zwróci dwa różne hasze i próba wykonania operacji w stylu where password_hash = ... nie ma w przypadku tego algorytmu sensu.
Ktos
No tak, ale sól jest zachowywana do wyniku (hasha) bcrypta - potem się z niego wyciąga sól i AFAIR koszt i z takimi parametrami hashuje podany ciąg przez użytkownika i jak wyjdzie to samo to znaczy że ciąg wejściowy był prawdopodobnie taki sam.
ŁF
@Korges: "Kodowanie podanego stałego hasła daje każdorazowo inny wynik. Następnie na zakodowanym haśle sprawdzamy hashcode i sprawdzamy z tym które podał użytkownik" - jeśli hash byłby za każdym razem inny, wtedy użytkownikowi życia by nie wystarczyło, żeby się zalogować.
lion137
  • Rejestracja:ponad 8 lat
  • Ostatnio:minuta
  • Postów:4951
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.


Patryk27
Nie każdy algorytm zawsze zwraca identyczny hash (np. bcrypt działa z wykorzystaniem dynamicznej soli).
katakrowa
@Patryk27 Na czym zatem polega weryfikacja poprawności hasła?
Patryk27
@katakrowa: na odkodowaniu pierwotnego hasha (tzn. na rozbiciu go na sól + "faktyczny" hash) i zahashowaniu sprawdzanego hasła z odkodowaną solą. Innymi słowy: dwukrotne wywołanie bcrypt() na tych samych danych wejściowych zwróci różne ciągi znaków, które należy porównywać z wykorzystaniem specjalnej funkcji (uwzględniającej fakt, że zwrócony hash zawiera w sobie dodatkowo sól).
katakrowa
Jakiś sens to ma ... dla mnie dziwne ale pewnie kryptolodzy i im podobni wiedzą czemu tak jest lepiej niż np. sha-3.
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:dzień
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.


edytowany 3x, ostatnio: ŁF
JA
Złoto, dziękuję :)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.