Van értelme a hash hashelésének?
Közelítsük meg a témát lépésről lépésre.
Ha több ezer, vagy több százezer usernek a jelszavát kaparintja meg valaki, akkor biztos lesznek benne olyan jelszavak (md5-el hashelve), amelyeket nyers erővel ki lehet találni. Ha valaki mondjuk egy szerver adatbázisát megszerezte, akkor esélyes, hogy a kódot is látja. Ha mégsem, akkor is játszhat olyat, hogy elkezd végigmenni a 6 karakteres jelszavakon, de nem csak az md5-öt, hanem az sha1-et, md5(md5), md5(sha1), sha1(md5), stb… kombinációkat is végigpróbálgatja. Vagy vannak ugye szivárványtáblák, ami egy nagy md5(str) → str adatbázis. Ezekben meg lehet találni a gyakori jelszavakat, de azoknak valószínű mindenféle kombinációit is. Ergo nem igazán éri meg egymásba ágyazni a hash-eket, mert ráadásul növeli az ütközés esélyét. Amit szoktak ez ellen tenni, hogy „megsózzák” a jelszót. Pl. nem az md5($password)-öt tárolják, hanem az md5($password . md5('ez itt az én saját sóm')). Ez sokat javít a visszafejtés esélytelenebbé tételén.
Ha jelszavakat kell hashelni, akkor nem csak a nyers erő, vagy egy szivárványtábla jöhet szóba. Ha százezer usernek van meg a hash-elt jelszava, akkor erősen valószínű, hogy többen használtak gyakori jelszavakat (password, 123456, stb…). Ezeknek az md5-je is azonos. De az md5(md5(md5($password))) is azonos. Nem is kell visszafejteni, egyszerűen gyakoriság alapján már lehet sejteni, hogy ha egy raklap embernek "5a22e6c339c96c9c0513a46e44c39683" a jelszava az adatbázisban, ez a leggyakoribb, akkor ez valószínű a "password" hash-e lesz, és ezen a statikus besózás sem segít, tök mindegy, milyen módon generálták. Erre megoldás, ha a só nem fix, hanem valamilyen adatból generálják, mondjuk az user id-jéből, nevéből, email címéből.
De még ez sem a legszerencsésebb, hiszen a hacker is gondolhat erre, ő is kísérletezhet vele. Meg alkalmasint ezek az adatok meg is változhatnak, és nem lehet automatikusan újragenerálni a jelszavak hash-ét, hiszen nem ismerjük az eredeti jelszót. De lehet azt is csinálni, hogy generálsz egy véletlen szöveget, vagy az aktuális időbélyegből, IP-ből összegyúrt valamit, és azzal sózod be a jelszót, és lemented az így kapott hash-t is, meg a sót is.
~ ~ ~ ~ ~ ~ ~
És akkor utolsó lépésként fogjuk meg az egészet, és felejtsük el. Mi a probléma? Az md5, sha1, sha256 és társaik mind-mind általános célú hash algoritmusok. Mondjuk használják ellenőrzőösszegnek is, és ott nagyon fontos, hogy gyorsak legyenek ezek a hash algoritmusok, hogy mondjuk egy több száz MB-os fájtból gyorsan lehessen hasht generálni. Pont ezért elemi utasításokkal operálnak, nagyon jól gyorsíthatóak mondjuk GPU-val, párhuzamosíthatóak. De ez a probléma velük a jelszó hashelésénél is, hiszen túl gyorsak, túl gyorsan lehet kipróbálni rengeteg jelszót. Ergo a jelszavak titkosításához olyan hash algoritmust lenne érdemes használni, ami kimondottan lassú, nem elemi utasításokból áll, nem gyorsítható GPU-val, nem párhuzamosítható, időigényes.
A PHP 5.5-től (ha jól rémlik) vezettek be egy külön függvénygyűjteményt, ami pont ennek ad egy keretet. Lásd: [link] . Ez egyelőre a bcrypt eljárást használja. Kicsit eltérő a használata a megszokottól.
A password_hash generál egy hash-t. Abban testre szabható a generáló algoritmus, és annak az „ára”, hogy mennyi processzoridőt zabáljon fel. Mondjuk így:
$options = array('cost' => 12);
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
Ha ugyanabból a jelszóból újra generálsz egy hash-t, akkor az egészen más lesz. Tehát az ellenőrzés sem a megszokott lesz:
if (md5($password) == $password_hash_in_database) …
Hanem kicsit fordítva ülünk fel a lóra:
if (password_verify($password, $password_hash_in_database)) …
(Persze az adatbázisból való lekérés is módosul, ha valaki addig úgy csinálta, mondjuk SELECT * FROM users WHERE name={$post_user_name} AND password={md5($post_user_password)}. Itt csak a bejelentkezési nevet/email címet/azonosítót kell feltételül megadni, a jelszó hash-ét később ellenőrizzük.)
Ha finomhangolni kell a rendszert, túlságosan lelassítja a túl magas cost a rendszert, vagy éppen túl gyengék a jelszavak, és erősebb cost-ot akarunk beállítani, akkor ezt is lehet ellenőrizni:
$options = array('cost'=>10);
if (password_needs_rehash($password_hash_in_database, PASSWORD_BCRYPT, $option)) {
/**/ $new_password_hash = password_hash($password, PASSWORD_BCRYPT, $options);
/* Ezt aztán lehet update-elni az adatbázisban */
}
Ez a megoldás minden szempontból ideális, faék egyszerűséggel használható.
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!