Opakované hašování
Už jsem psal o tom, jak rychle se dají vypočítat haše krátkých hesel. Pokud nechceme uživatele nutit k používání dlouhých hesel, tak bychom potřebovali hašování nějak zpomalit. Jednoduchý způsob je volat hašovací funkci opakovaně:
<?php
$hash = $_POST["password"];
for ($i=0; $i < 1000; $i++) {
$hash = md5($hash);
}
?>
Tomuto postupu se říká zesilování hesla. O tomto postupu se zmiňuje i článek o ukládání hesel vydaný v rámci měsíce bezpečnosti PHP. Místo funkce md5 se dá volat i jiná funkce, můžeme přidat salt, to ale v tuto chvíli není zajímavé.
Teoretická komplikace
Při opakovaném hašování může teoreticky docházet ke vzniku cyklů. Když by nějaká primitivní hašovací funkce hašovala a1 na b2, b2 na c3 a c3 na a1, tak by všechna hesla, která se v některé fázi opakovaného hašování zahašují na jeden z těchto kódů, splynula v pouhá tři různá hesla. Jinými slovy by se podstatně zvýšilo riziko kolize.
Přijďte si o tomto tématu popovídat na školení Bezpečnost PHP aplikací (8.10.2010, Praha).
Diskuse
honza:
opakovane hashovani ma velky vyznam v pripade potencionalniho utoku. Pri slovnikovem utoku bude utocnik muset provest 100x operaci coz ho vyrazne spomali.
vasio:
Dovolim si nesouhlasit, při slovníkovém útoku by to mělo být jedno jestli je to 100x nebo 1000000x hašovaný, při přihlašování se to přeci nijak neprojeví snad v mikrosekundách na odezvě serveru ;-), omluvte mně pokud se mílím, možná jsem mimo :)
vasio:
Pardón, vy řešíte situaci kdy útočník již hash má, sorry za můj nepředmětný komentář.
Chtěl jsem se zeptat, k čemu je důležité/výhodné zpomalit samotný proces hashování?
Když má útočník seznam hašů a snaží se z nich zjistit původní heslo, tak to může udělat hrubou silou – zkouší buď všechny kombinace povolených znaků nebo jede podle nějakého slovníku. Při jednoduchém hašování stihne vyzkoušet třeba milión hesel za sekundu, při tisícinásobném jen tisíc. Sníží se tedy počet hesel, které je schopen v daném čase odhalit.
Nezdá sa mi že 1000-násobné zahashovanie je dobrý nápad ako "spomaliť hašovanie". Ono stačí spraviť hash pár-krát a spomalenie zabezpečiť inak, napríklad použitím funkcie sleep():
<?php
$hash=md5(md5($password).$salt);
sleep(1);
?>
Aha, podľa tvojho predchádzajúceho komentára ti ide o situáciu, kedy útočník má prístup k dátam z databázy a vie aj akým spôsobom je hash vytváraný (čiže PHP skript). V tom prípade je môj komentár bezpredmetný.
majak:
V tomto článku sa píše, že na účely uchovávania hesiel je vhodné použiť funkciu bcrypt:
http://codahale.com/how-to-safely-store-a-password/Jej výhodou je, že hashovanie trvá dlhšie (dá sa nastaviť "work factor") a zároveň by sa tým nemalo zvýšiť riziko kolízie.
Nevýhodou je, že táto funkcia je v PHP určite dostupná až od verzie 5.3, v starších jej dostupnosť závisí od systému.
Konkrétne sa jedná o funkciu crypt, typ Blowfish:
http://php.net/manual/en/function.crypt.php
paranoiq:
pokud jsem to správně pochopil, tak work factor v podstatě znamená počet opakování ($rounds=5000). např. samotná blowfish je v základu pouze dvakrát pomalejší než SHA-2 (
http://www.cryptopp.com/benchmarks.html). není tedy důvod spoléhat na přítomnost téhle knihovny
Anebo tedy mcrypt, který je od PHP4.0.2 a snad i běžně dostupný, alespoň většinou ho vídám povolený (na hostinzích)