Czy da się przechowywać hasło użytkownika w taki sposób aby móc je zweryfikować podczas logowania ale nie znać jego treści? Brzmi to jak niezły paradoks, prawda? Okazuje się, że istnieje sposób aby tego dokonać. Wykorzystuje się w tym celu właśnie tytułowe funkcje skrótu.

Trochę teorii

Funkcje skrótu, nazywane często funkcjami haszującymi, to funkcje generujące unikatowy, stałej długości skrót z dowolnej ilości danych. Ważne jest również to aby taka funkcja była jednokierunkowa. Znaczy to tyle, że na podstawie skrótu nie jesteśmy w stanie wygenerować danych, z którego on powstał.

Nawet minimalna modyfikacja danych powoduje diametralną zmianę ich skrótu. Poniżej przykład z zastosowaniem funkcji haszującej SHA-1. Na czerwono zaznaczyłem różnicę w obu zdaniach.

Dane Skrót SHA-1
becomeapro.pl to najlepsza strona internetowa pod słońcem
c94363dfee89e19b5f71e9d587a64f256f587ef7
becomeapro.pl to najlepsza strona internetowa pod słoncem
8809bdb9b54cd615c2a0b55cea32d4e2803b28a2

Bez względu na ilość haszowanych danych skrót będzie miał zawsze jednakową długość.

Dane Skrót SHA-1
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus nec dictum ex. Sed pulvinar enim lacus, at mattis nulla porttitor in. Curabitur in pretium turpis. Donec pretium, massa at venenatis varius, enim ligula elementum tellus, ac luctus arcu turpis ac nulla. Ut leo ligula, dignissim a tellus sit amet, ultrices vestibulum quam. Ut laoreet velit sit amet ex suscipit, vel tempor justo auctor. Sed at nulla at orci faucibus porttitor at in arcu. Duis efficitur ipsum efficitur augue ullamcorper pellentesque. Donec faucibus consectetur lorem, interdum rhoncus metus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas vulputate a lacus eu laoreet. Etiam commodo consequat elit eu posuere. Phasellus tempus vitae nunc nec vehicula. Nulla venenatis accumsan semper. Nunc enim orci, laoreet eu posuere at, maximus vel risus.
9c31a0bfeb70fab64ee2d99db46edb25afc1012f
ABC
3c01bdbb26f358bab27f267924aa2c9a03fcfdb8

Na deser stworzyłem małe demo, które haszuje wprowadzony tekst wybraną przez Ciebie funkcją skrótu.

Jak to wszystko ma się do haseł?

Podczas procesu uwierzytelniania użytkownika zachodzi potrzeba sprawdzenia czy podane przez niego hasło jest prawidłowe. Oczywiste prawda?

Jaką wadę ma to rozwiązanie? Hasło przechowywane jest w formie jawnej i w razie włamania atakujący będzie w stanie je bez problemu poznać. Wbrew pozorom takie sytuacje zdarzają się często. Niestety… Możesz się o tym przekonać wchodząc na stronę haveibeenpwned.com gdzie podając swojego maila bądź nazwę użytkownika sprawdzisz czy jesteś ofiarą któregoś z dużych wycieków baz danych.

Na szczęście jako programiści możemy utrudnić atakującemu zadanie tak aby w razie włamania nie był w stanie poznać haseł naszych użytkowników. Wystarczy, że przechowamy je w naszej bazie danych w formie haszy:

Musimy również zmodyfikować kod odpowiedzialny za weryfikację użytkowników. Funkcja licząca skrót SHA-1 pochodzi z przykładu z GitHuba.

Teraz w razie nieautoryzowanego dostępu do bazy danych atakujący będzie miał nie lada wyzwanie aby poznać oryginały haseł.

Sól i tęczowe tablice

Okazuje się, że same funkcje skrótu nie są wystarczającą warstwą obrony przed potencjalnymi atakującymi. Przecież przeciętny użytkownik nie używa długich i skomplikowanych haseł. A gdyby tak stworzyć bazę danych różnych kombinacji haseł i ich skrótów?

Rainbow

Takie bazy danych są nazywane właśnie rainbow tables czyli tęczowe tablice. Zwykle zajmują setki gigabajtów ale umożliwiają stosunkowo szybkie odzyskanie haseł na podstawie hashy. Genialne w swojej prostocie, prawda? Poniżej masz zestaw kilku haseł zahaszowanych algorytmem MD5. Spróbuj je złamać przy pomocy strony crackstation.net, która korzysta właśnie z tęczowych tablic.

098f6bcd4621d373cade4e832627b4f6
49aa66843380c377e93b198b966eb699
bbb2c5e63d2ef893106fdd0d797aa97a
34819d7beeabb9260a5c854bc85b3e44
7df254d0fdbbc64a9317265a5084a29b

Udało się?

Jak się przed tym bronić?

Tutaj z pomocą przychodzi nam właśnie wspomniana wcześniej sól. Jest to losowo generowana wartość dodawana do danych przed ich zahaszowaniem. Jeśli chcielibyśmy złamać posolone wcześniej hasła musielibyśmy wygenerować tyle tęczowych tablic ile soli jest w bazie danych. Pamiętasz jak wspominałem ile pamięci potrafią zajmować? Setki gigabajtów! Właśnie to ograniczenie czyni ten atak niepraktycznym (co nie znaczy, że niemożliwym 😉 ).

Przykład? Rozważmy sobie taki zestaw danych:

W tabeli mamy dwóch użytkowników, którzy mają takie same hasła. Dlaczego ich skróty są różne? To właśnie dzięki zastosowaniu soli. Poniżej nasz kod zmodyfikowany w taki sposób aby był w stanie obsługiwać solone hasła.

Tylko tyle i aż tyle.

Podsumowanie

Jak widać w stosunkowo prosty sposób możemy zapewnić dodatkową warstwę ochrony danych użytkowników naszych aplikacji. Jednak nie dajmy się zwieść pozorom. Napastnik, który ma wystarczająco dużo cierpliwości i zasobów prędzej czy później i tak pozna zabezpieczone w ten sposób hasła. Warto jednak zapewnić sobie czas na ewentualne poinformowanie użytkowników o konieczności ich zmiany. Jeśli interesujesz się tą tematyką polecam obejrzeć sobie prelekcję Pana Marcina Rybaka z konferencji SECURE 2016 o wymownym tytule „Wczoraj złamałem Twoje hasło, jutro złamię je ponownie„. Daje do myślenia.