Co liczy generator hash i czym jest funkcja skrótu
Funkcja skrótu zamienia dane dowolnej długości na ciąg o stałej długości. MD5 zawsze zwraca 128 bitów zapisanych jako 32 znaki szesnastkowe, a SHA-256 daje 256 bitów, czyli 64 znaki. Ta sama treść zawsze daje ten sam hash, a najmniejsza zmiana wejścia zmienia wynik nie do poznania. Kryptograficzna funkcja skrótu dokłada do tego wymóg, żeby z samego wyniku nie dało się odtworzyć wejścia ani dobrać drugiego zestawu danych o identycznej wartości.
Najczęstsze praktyczne zastosowanie to sprawdzenie integralności danych, czyli tego, czy pobrany plik jest identyczny z tym, który opublikował wydawca. Dystrybucje Linuksa i duże instalatory publikują obok pliku jego sumę SHA-256. Policz hash lokalnie i porównaj oba ciągi znak po znaku albo wklej wartość odniesienia do pola porównania w tym narzędziu.
W kodzie ten sam wynik daje jedna linia, bo PHP ma funkcję hash('sha256', ...), MySQL i PostgreSQL wbudowane MD5(), a Python moduł hashlib, przy czym nazwy algorytmów zapisuje się w bibliotekach bez łącznika i SHA-1 występuje tam jako sha1. Kolumna z wynikiem MD5() bywa w starszych bazach używana do haseł i jest to dziś podatność, którą łata się przejściem na password_hash() z bcryptem.
Dlaczego hashe MD5 i SHA-1 uznano za złamane
Bezpieczna funkcja skrótu musi utrudniać znalezienie dwóch różnych danych dających ten sam wynik, a taka para nazywa się kolizją. Dla MD5 kolizje potrafi wygenerować zwykły komputer w kilka sekund, a pierwsze praktyczne ataki opisano już w 2004 roku. SHA-1 wytrzymał dłużej, ale w 2017 roku zespół badaczy pokazał kolizję dwóch różnych plików PDF, a w 2020 roku ogłoszono atak, który dobiera kolizję do wybranego z góry prefiksu.
Konsekwencja praktyczna jest taka, że hash MD5 nie dowodzi, od kogo plik pochodzi, bo złośliwy plik można spreparować tak, by miał tę samą sumę co plik nieszkodliwy. Do wykrycia zwykłego uszkodzenia przy transmisji MD5 wciąż wystarcza, bo losowy błąd na pewno zmieni skrót. Granica przebiega między wykrywaniem przypadkowego błędu a wykrywaniem celowej podmiany i to ona rozstrzyga, czy suma MD5 cokolwiek w danej sytuacji potwierdza.
Czym jest HMAC i kiedy się go używa
Zwykły hash nie ma sekretu, bo policzyć go może każdy. HMAC dodaje klucz, a wynik odtworzy wyłącznie ten, kto ten klucz zna. Algorytm opisany w RFC 2104 liczy skrót dwukrotnie, najpierw z kluczem uzupełnionym stałą wewnętrzną, potem z kluczem uzupełnionym stałą zewnętrzną. Ta konstrukcja chroni przed atakiem, w którym napastnik dopisuje własną treść do przechwyconej wiadomości.
W praktyce spotkasz HMAC wszędzie tam, gdzie dwa systemy muszą sprawdzić autentyczność komunikatu, czyli w podpisach webhooków od bramek płatniczych, w tokenach JWT z algorytmem HS256, w podpisywaniu zapytań do interfejsów chmurowych i w podpisanych ciasteczkach sesyjnych. HMAC z MD5 wypada zauważalnie lepiej niż samo MD5, bo ataki kolizyjne nie przenoszą się bezpośrednio na konstrukcję z kluczem, choć do nowych rozwiązań stosuje się HMAC-SHA256.
Hash pliku, czyli po co czytać go porcjami
Wczytanie kilkugigabajtowego pliku do pamięci naraz zwykle kończy się zawieszeniem karty przeglądarki. Dlatego plik jest tutaj dzielony na porcje po 4 MB, a stan funkcji skrótu przenosi się między nimi. Ten sposób pracy nazywa się przetwarzaniem strumieniowym i robią to samo narzędzia systemowe w rodzaju sha256sum i sha1sum.
Dla rodziny SHA przeglądarka udostępnia tylko interfejs jednorazowy, który wymaga całej zawartości naraz, więc przy dużych plikach liczymy hash przyrostowo tam, gdzie to możliwe, a pozostałe algorytmy przetwarzamy po zbuforowaniu porcji. Pasek postępu pod polem wyboru pliku pokazuje, ile już przeczytano.
Dlaczego hash nie nadaje się do przechowywania haseł
Funkcje skrótu zaprojektowano tak, żeby były szybkie. To zaleta przy sumach kontrolnych i wada przy hasłach, bo współczesna karta graficzna liczy dziesiątki miliardów skrótów SHA-256 na sekundę, a przejście przez wszystkie hasła ośmioznakowe jest wtedy kwestią godzin. Dodanie soli utrudnia użycie gotowych tablic, ale nie spowalnia samego liczenia.
Do haseł stosuje się funkcje celowo powolne, a w nowszych konstrukcjach też pamięciożerne, czyli bcrypt, scrypt, PBKDF2 i Argon2, który wygrał konkurs Password Hashing Competition w 2015 roku. Ich parametry dobiera się tak, żeby pojedyncze sprawdzenie hasła trwało kilkadziesiąt milisekund. Dla użytkownika to czas niezauważalny, dla atakującego to różnica między godzinami a stuleciami.