Proces hashování (na rozdíl od šifrování) ze vstupu vytvoří takový výstup, z kterého již nelze odvodit původní řetězec.
Výborně se proto hodí pro ochranu citlivých řetězců, hesel a kontrolní součty.
Další příjemná vlastnost hashovacích funkcí je, že generují výstupy vždy se stejnou délkou a malá změna na vstupu vždy kompletně změní celý výstup.
V PHP existuje mnoho hashovacích funkcí, ty důležité jsou:
$password = 'tajne-heslo';echo password_hash($password); // Bcryptecho md5($password);echo sha1($password);
Pozor: Funkce
md5()
anisha1()
není vhodná k hashování hesel, protože je výpočetně jednoduché původní heslo odhalit, nebo si hesla aspoň předpočítat. Mnohem lepší je použítbcrypt
, který pro hashování hesel vznikl.Web md5cracker.com obsahuje databázi kontrolních součtů (hashů), zkuste vyhledat třeba hash:
79c2b46ce2594ecbcb5b73e928345492
, jak je vidět, tak čistémd5()
není zas tak bezpečné pro častá slova a hesla.
Bcrypt + salt
Na přednášce Jak to nepokazit v cílové rovince řešil David Grudl způsoby, jak správně hashovat a ukládat hesla.
Jediné správné řešení je: Bcrypt + salt
.
Konkrétně:
$password = 'hash';// Vygeneruje bezpečný hashecho password_hash($password, PASSWORD_BCRYPT);// Případně s vyšší složitostí (výchozí je 10):echo password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
Výhoda Bcrypu je hlavně v jeho rychlosti a automatickém solení.
Díky tomu, že generování trvá dlouho, třeba 100 ms, tak je pro útočníka velmi drahé testovat mnoho hesel.
Výstupní hash je navíc automaticky ošetřen pomocí náhodné sole, díky které při opakovaném hashování stejného hesla je na výstupu vždy jiný hash. Útočník proto nebude moci použít předpočítanou tabulku hashů.
Správnost hesla proto nebudeme moci ověřit opakovaným hashováním, ale bude potřeba zavolat specializovanou funkci:
if (password_verify($password, $hash)) {// Heslo je správně} else {// Heslo není správně}
Aby bylo prolomení hashů složitější, je dobrý nápad do originálního vstupu vkládat nějaký další řetězec. V ideálním případě náhodný. Tomuto procesu se říká solení hesel.
Bezpečnost je založena na myšlence, že útočník nebude moci použít předpočítanou tabulku hesel a hashů, protože nebude znát sůl a bude muset hesla lámat jednotlivě.
Například:
$password = 'tajne_heslo';$salt = 'fghjgtzjjhg';$hash = md5($password . $salt);echo $password; // vypíše původní hesloecho $hash; // vypíše hash hesla včetně soli
Možná vás napadá, že by byl dobrý nápad hashovací funkci provést opakovaně a tím zvednout složitost prolomení, protože bude potřeba originální heslo opakovaně hashovat.
Například:
$password = 'heslo';for ($i = 0; $i <= 1000; $i++) {$password = md5($password);}echo $password; // 1000x zahashováno přes md5()
Tímto postupem se náročnost prolomení paradoxně snižuje, nebo zůstává téměř stejná.
Důvod je ten, že funkce md5()
je extrémně rychlá a na běžné počítači lze spočítat přes milion hashů za sekundu, proto se postupné zkoušení hesel o moc nezpomalí.
Druhý důvod je spíše teorie, a to možnost narazit na tzv. kolizi. Pokud budeme heslo opakovaně hashovat, časem se může stát, že se trefíme do hashe, který už útočník zná a díky tomu bude moci heslo promolit pomocí databáze.
Lepší je proto použít pomalou bezpečnou hashovací funkci a provádět hashování pouze jednou, přičemž se finální výstup ještě ošetří solením.
Věděli jste, že operátor === není pro porovnání hashů při ověřování hesla nejbezpečnější volba?
Při porovnávání řetězců se prochází oba řetězce znak po znaku, dokud se nedojde na konec (úspěch, jsou stejné), nebo nenastane rozdíl (stringy jsou různé).
A toho se dá při útoku využít. Když budete dostatečně přesně měřit čas, lze odhadnout, kolik znaků ještě zbývá doplnit, abyste měli přesnou shodu a došlo se na konec, resp. lze odhadnout, jak daleko se při porovnání řetězců došlo.
Řešením je použít funkci hash_equals() všude, kde se porovnávají řetězce a vadilo by, kdyby útočník mohl zjistit pozici, kde porovnání selhalo.
A jak to funkce dělá? Zajistí, aby porovnání libovolných 2 řetězců trvalo vždy stejně, takže nelze měřením času zjistit, kde došlo k rozdílu. Některé typy útoků mi přijdou opravdu velmi nepravděpodobné a těžko proveditelné. Tohle zrovna patří mezi ně.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Nabízím trénink vývojářů, konzultace, školení a analýzu návrhových vzorů. Osobně v Praze nebo online.
Napište mi, pokud si nevíte rady.
Lektor: Jan Barášek
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | cs