A PHP 5.5 új jelszókezelő függvényei
2013. 06. 03.
A PHP 5.5-ös verziójától kezdve elérhető lesz néhány új függvény, amelyek a jelszavak kezelését segítik. Ezekről fogok írni most, hogy miért volt rájuk szükség, miért kerültek be a PHP magjába, és hogyan lehet őket használni.
Háttér
Hiába ismert az MD5-ben egy hiba 1996, a SHA1-ben pedig 2005 óta, a mai napig ezek azok a függvények, amelyeket a PHP-ban programozók többsége használ a jelszavak egyirányú kódolására (hash-selérére). Rossz esetben salt nélkül, kicsit jobb esetben egy jelszavanként különböző salttal.
Akárhogy is, ezekben egy hiba közös: sem az MD5, sem az SHA1 nem erre lett megalkotva. Mindkettőnek eredeti célja az, hogy üzenetek gyors integritás-ellenőrzését tegyék lehetővé – tehát fontos szempont volt tervezésükkor, hogy gyorsak legyenek, és egyszerűen meg lehessen őket valósítani áramkörök szintjén. Pontosan ez a sebesség teszi őket alkalmatlanná arra, hogy jelszavakat biztonságosan tároljunk benne.
2012 májusában Anthony Ferrara hozta létre a problémát megoldani célzott RFC-t, amit érdemes végigolvasni. Ebben részletesen leírja, mi a probléma a jelenlegi helyzettel. Mindössze négy új függvényt ír le azzal a céllal, hogy olyan egyszerű legyen a használata: balgaság legyen bárhogy máshogy csinálni.
A függvények
password_hash
Ezzel tudod hashelni a jelszót új felhasználó létrehozásakor.
string password_hash(string $password, int $algo, array $options = array())
Az első paraméter maga a kódolandó jelszó, a második a használandó algoritmus. Kettő konstans van erre definiálva, a PASSWORD_BCRYPT
és a PASSWORD_DEFAULT
. Jelenleg mindkettőnek ugyanaz az értéke, de ha később egy erősebb algoritmus is beépítésre kerül, a default arra fog módosulni.
Az opciók közt két értéket adhatunk meg: az egyik a salt
, amit ha kihagyunk, random generál egyet; a másik a cost
, ami az algoritmus műveletigényére van hatással. Ezt érdemes úgy belőni, hogy egy másodperc körüli idő alatt számoljon egy hasht. Érvényes bármely 4 és 30 közti egész, az alapértelmezett a 10.
Visszatérési értéke bcrypt esetén egy fix 60 karakteres string, ami tartalmaz mindent, amire ellenőrzéshez szükségünk van, azaz elég ezt mentenünk.
password_verify
Ezzel lehet ellenőrizni bejelentkezéskor, helyes jelszót adott-e meg a felhasználó.
bool password_verify($password, $hash)
Két paramétert vár, az első a kapott jelszó, a második a korábban mentett hash. Azt adja vissza, stimmel-e.
Érdekesség, hogy a háttérben egy olyan string-összehasonlító függvényt használ, ami ellenálló az időzítéses támadásokkal szemben: nem tér vissza hamissal az első eltérésnél, hanem mindenképp végignézi mindkét stringet.
password_needs_rehash
Ezzel azt tudod eldönteni, szükséges-e a jelszó újrakódolása azért, mert a rendszer közben átállt új algoritmusra, vagy nagyobb költségre. A bejelentkezési folyamat részeként lehet használni, amikor megvan a kódolatlan jelszó is.
bool password_needs_rehash(string $hash, int $algo, array $options = array())
Paraméterei annyiban térnek el a password_hash
-étől, hogy ez egy már kódolt jelszót vár, nem egy eredetit. Azt adja vissza, gyengébb paraméterekkel (algoritmus, költség) lett-e hash-elve, mint amit kapott.
password_get_info
Ezzel tudod egy hash kódoláskor megadott paramétereit.
array password_get_info(string $hash)
A visszatérési értéke egy tömb algo
és options
kulcsokkal, az első a használt algoritmust adja meg, a második az annak átadott paramétereket, mint például a költség.
Használati példa
Az alábbi példa a fentebb linkelt RFC-ből származik. Megmutatja, hogy kell egy kapott jelszót hash-elni adott paraméterekkel, azt ellenőrizni, illetve megnézni, szükséges-e az újbóli kódolás.
<?php
$password = "rasmuslerdorf";
$hash = password_hash($password, PASSWORD_BCRYPT, array(
"cost" => 7,
"salt" => "usesomesillystringfor",
)));
if (password_verify($password, $hash)) {
if (password_needs_rehash($hash, PASSWORD_BCRYPT, array(
'cost' => 8,
))) {
update_password_in_db($password);
}
log_user_in();
} else {
error_wrong_password();
}
Az jól látható, hogy innentől felesleges egyéb megoldásokat használni, ennél tényleg nem lehet egyszerűbb.
És 5.5 előtt?
Nem kell félni attól, hogy ezek csak évek múltán lennének használhatók, amikor már a szolgáltatók többsége átállt 5.5-re. Az eredeti, C nyelvű patch szerzője megvalósította ugyanazt PHP-ban is password_compat néven, ezt már 5.3.7-től kezdve lehet használni. Működése pontosan ugyanaz, mint a majdani beépített függvényeké.