Aktuális helyzet: PHP2Shell. Két kritikus PHP-rés (CVSS 9,2) lehetővé teszi kártékony kód futtatását bejelentkezés nélkül. Javítások 2026. 10. 21. óta.Mi a teendő most →

Jelszavak biztonságos tárolása PHP-ban: a password_hash helyes használata

Hogyan tárolják a fejlesztők a jelszavakat PHP-ban a password_hash és a password_verify segítségével, hogyan választják ki a megfelelő eljárást, és hogyan váltják le a régi MD5- vagy SHA-1-hasheket anélkül, hogy minden felhasználónak jelszót kellene visszaállítania.

Állapot 5 perc olvasási időBiztonságos fejlesztés

Röviden: A jelszavakat PHP-ban a password_hash() függvénnyel tárolja, és a password_verify() függvénnyel ellenőrzi. A PASSWORD_DEFAULT alapértelmezés jelenleg bcryptet használ, a PHP 8.4 óta 12-es költségtényezővel; ahol a PHP Argon2-vel van fordítva, a PASSWORD_ARGON2ID jó alternatíva. A régi MD5- vagy SHA-1-hasheket úgy állítja át, hogy azonnal beágyazza őket a password_hash-be, és a következő bejelentkezéskor közvetlen hashre cseréli.

Mi köze egy adatbázis-kiszivárgásnak a hasheihez

Egy webszerver feltörése után az adatbázis az egyik első cél. Aki, ahogyan a PHP2Shellnél lehetséges, kódot tud végrehajtani a szerveren, az alkalmazás hozzáférési adatait is elolvassa, és ezzel a felhasználói fiókok táblázatát is. Hogy a benne lévő jelszavak órák vagy évek múlva válnak-e olvashatóvá, az nem a támadás napján dől el, hanem a programozáskor.

Meglepően sok alkalmazás ma is olyan eljárásokkal tárolja a jelszavakat, amelyeket erre a célra soha nem szántak: MD5, SHA-1, egyszerű SHA-256, vagy akár visszafordíthatóan titkosítva. Ezek az eljárások gyorsak, és éppen ez a baj. A támadók velük másodpercenként nagyon sok jelöltet végigpróbálhatnak.

A PHP régóta hoz magával egy megoldást, amely lassan számol, minden jelszóhoz automatikusan sót generál, az eljárást és a paramétereket pedig magában a hashben tárolja. Önnek csak következetesen használnia kell.

password_hash PHP-ban: bcrypt vagy Argon2id?

A password_hash() több eljárást ismer. A választék a PHP kézikönyve szerint:

Konstans Eljárás Megjegyzés
PASSWORD_DEFAULT jelenleg bcrypt alapértelmezés, a jövőbeli verziókban változhat
PASSWORD_BCRYPT bcrypt költségtényező a PHP 8.4 óta alapból 12, korábban 10; csak az első 72 bájt számít
PASSWORD_ARGON2I Argon2i a PHP 7.2 óta, csak ha a PHP Argon2-támogatással készült
PASSWORD_ARGON2ID Argon2id a PHP 7.3 óta, ugyanez a feltétel

Az OWASP az Argon2id-t ajánlja első választásként, legalább 19 MiB memóriával, két futással és egy szállal, a bcryptet pedig főleg meglévő rendszerekhez. A legtöbb PHP-alkalmazásnál a gyakorlatban kisebb a különbség, mint e eljárások bármelyike és az MD5 között. Fontosabb, hogy egyáltalán használja valamelyiket, és rendszeresen igazítsa a paramétereket.

Hogy elérhető-e az Argon2id, azt egy rövid teszt mutatja:

<?php
var_dump(defined('PASSWORD_ARGON2ID'));
var_dump(password_algos());

Tárolás és ellenőrzés: egy teljes minta

A következő példa a regisztrációt és a bejelentkezést mutatja a régi hashek automatikus frissítésével. A hosszellenőrzés védelmet nyújt a bcrypt 72 bájtos határa ellen:

<?php
declare(strict_types=1);

const PASSWORT_ALGO = PASSWORD_DEFAULT;

function passwortSpeichern(string $passwort): string
{
    if (strlen($passwort) > 72) {
        throw new InvalidArgumentException('Passwort zu lang für das gewählte Verfahren.');
    }
    return password_hash($passwort, PASSWORT_ALGO);
}

function passwortPruefen(string $eingabe, string $gespeicherterHash, callable $hashAktualisieren): bool
{
    if (!password_verify($eingabe, $gespeicherterHash)) {
        return false;
    }
    if (password_needs_rehash($gespeicherterHash, PASSWORT_ALGO)) {
        $hashAktualisieren(password_hash($eingabe, PASSWORT_ALGO));
    }
    return true;
}

A strlen() bájtokat számol, nem karaktereket. Ez itt szándékos, mert a bcrypt határa bájtokra vonatkozik. Az adatbázisbeli oszlopnak a kézikönyv szerint 60 karakternél többet kell tartalmaznia, a 255 jó választás. Soha ne adjon meg saját sót: ez a beállítás elavult, és a PHP 8.0 óta figyelmen kívül marad.

A PHP 8.4-re váltással a bcrypt alapértelmezett költségtényezője 10-ről 12-re emelkedik. A meglévő hasheket a password_needs_rehash() révén a következő bejelentkezéskor automatikusan megemeli a rendszer. Erősen terhelt rendszereken az átállás előtt érdemes egy rövid terhelési tesztet futtatni a bejelentkezésen.

Tipp

Mérje meg a költségtényezőt az éles szerverén. Egyetlen ellenőrzésnek érezhető számítási időbe kell kerülnie, de egy másodperc alatt kell maradnia, hogy a bejelentkezések terhelés alatt ne váljanak szűk keresztmetszetté.

A régi MD5- és SHA-1-hashek leváltása

Az igazi kihívás általában a meglévő állomány. Magukat a jelszavakat nem ismeri, ezért nem hasheli őket egyszerűen újra. Ha megvárja, amíg minden felhasználó újra bejelentkezik, az inaktív fiókok védelem nélkül maradnak. Az OWASP ezért kétlépcsős eljárást ír le:

  1. Azonnali beágyazás: minden meglévő MD5- vagy SHA-1-értéket szkripttel password_hash()-be burkolni, és jelöléssel tárolni, például egy hash_typ oszlopban.
  2. Ellenőrzés bejelentkezéskor: a jelölt fiókoknál a bevitelt először a régi eljárással átszámolni, majd a password_verify() függvénnyel a burkolt értékhez hasonlítani.
  3. Közvetlen csere: sikeres bejelentkezés után a nyílt szövegből normál hasht létrehozni, és a jelölést eltávolítani.
  4. A maradék rendezése: azokat a fiókokat, amelyeknek egy meghatározott határidő után még burkolt hasheik vannak, jelszó-visszaállításra állítani.
<?php
// 1. szint (egyszeri szkripttel): $neu = password_hash($alterMd5Wert, PASSWORD_DEFAULT);
// 2. és 3. szint bejelentkezéskor:
if ($konto['hash_typ'] === 'md5-umhuellt') {
    $ok = password_verify(md5($eingabe), $konto['passwort_hash']);
    if ($ok) {
        $speichere(password_hash($eingabe, PASSWORD_DEFAULT), 'direkt');
    }
}

A burkolt hashek jobbak a puszta MD5-értékeknél, de gyengébbek a közvetlen hasheknél. Átmeneti megoldások, nem célok. Egy olyan incidens után, amelyben az adatbázis érintett lehet, ez az átállás nem helyettesíti a felhasználók felszólítását jelszavuk megváltoztatására. Hogy milyen nyomok utalnak ilyen incidensre, azt a Már feltörték a rendszeremet? írja le.

Pepper, titkosítás és más tévutak

Néhány ötlet több biztonságnak hangzik, de keveset hoz, vagy árt:

  • Saját hash-konstrukciók, például többszörös SHA-256 saját sóval, gyorsabbak a bcryptnél, ezért gyengébbek.
  • A titkosított jelszavak visszafordíthatók. Ha a kulcs ugyanazon a szerveren van, a titkosítás egy betörés után alig véd.
  • A pepper, vagyis egy titkos kiegészítő érték az összes jelszóhoz, további réteg lehet, ha az adatbázistól elkülönítve őrzik. Jó hash-eljárást azonban nem helyettesít, és megnehezíti a későbbi váltásokat.
  • A bcrypt előtti előzetes hashelés a 72 bájtos határ megkerülésére az OWASP szerint saját kockázatokat rejt. Egy egyértelmű hosszkorlát vagy az Argon2id egyszerűbb.

Az új jelszavakra vonatkozó szabályoknál is érdemes a technika állására nézni: a hossz többet véd, mint a különleges karakterekre vonatkozó bonyolult előírások, a nagyon gyakori vagy már adatszivárgásokban felbukkant jelszavakat pedig el kell utasítani. Az ok nélküli, rögzített időközönként kikényszerített jelszócserék tapasztalat szerint inkább kiszámítható mintákhoz vezetnek, mint erősebb jelszavakhoz.

A bejelentkező rendszereknél a jelszavak ráadásul soha nem állnak egyedül: az adminok kétfaktoros eljárása és a tömeges bejelentkezési kísérletek fékezése kiegészíti a tárolást. Mindkettővel foglalkozik az Admin bejelentkezések védelme a brute force ellen útmutató. A visszaállító linkekre és az egyszeri kódokra más szabályok vonatkoznak, lásd Biztonságos véletlenszámok és tokenek PHP-ban. További funkciókról áttekintést ad a A PHP beépített biztonsági funkciói.

Hogyan segít konkrétan a PHP SOS?

  • Ellenőrizzük, hogyan tárolja a jelszavakat az alkalmazása és a bővítményei, és a mellékfunkciókban is megtaláljuk az elavult eljárásokat.
  • Megtervezzük a meglévő állomány átállítását burkolással, bejelentkezéskori migrációval és határidővel a maradék fiókokra.
  • A költségtényezőt vagy az Argon2-paramétereket a szervereire hangoljuk.
  • Egy incidens után támogatást nyújtunk a jelszó-visszaállításokról szóló döntésben és a technikai megvalósításukban.

A saját PHP-szoftver ellenőrzését biztonsági auditként és penetrációs tesztként kínáljuk.

Gyakori kérdések

Melyik algoritmust használja a password_hash a PASSWORD_DEFAULT-tal?

Jelenleg a bcryptet. A PHP kézikönyve rámutat, hogy az alapértelmezés változhat, ha erősebb eljárások kerülnek be. Ezért az adatbázis-oszlopnak 60 karakternél többet kell tartalmaznia; a kézikönyv a 255-öt nevezi jó választásnak.

Titkosítsam a jelszavakat hashelés helyett?

Nem. A titkosított jelszavak a kulccsal újra olvashatóvá tehetők, ez a kulcs pedig többnyire ugyanazon a szerveren van. A jelszó-hash egyirányú utca: az alkalmazás csak azt tudja ellenőrizni, hogy egy bevitel megfelel-e.

Milyen magas legyen a költségtényező a bcryptnél?

A PHP 8.4 óta az alapértelmezés 12, korábban 10 volt. Az OWASP a 10-et nevezi alsó határnak, és azt javasolja, hogy olyan magasra menjen, amennyit a szerverei elbírnak. Mérje meg a saját hardverén, mennyi ideig tart egy ellenőrzés.

Mit jelent a 72 bájtos határ a bcryptnél?

A bcrypt csak egy jelszó első 72 bájtját veszi figyelembe, ami utána jön, azt levágja. Ékezetes karaktereknél egy karakter gyakran két bájtnak számít. Ezért kifejezetten korlátozza a hosszt, vagy használja az Argon2id-t, ha a PHP-je azzal lett fordítva.

Meg kell változtatniuk a felhasználóknak a jelszavukat egy betörés után?

Ha nem zárható ki, hogy az adatbázis kiszivárgott, ezt kezdeményeznie kell. A jó hashek jelentősen lassítják a törést, a gyenge jelszavak azonban támadhatók maradnak. Hogy van-e emellett bejelentési kötelezettség, azt egyeztesse az adatvédelmi tisztviselőjével.

Források

Azonnali kapcsolat

Minden óra számít. Írjon nekünk most.

Ismertesse röviden a rendszert, a PHP-verziót és a megfigyelését. Jelentkezünk, tisztázzuk a helyzetet, és távolról dolgozunk, amíg az incidens le nem zárul és dokumentálva nem lesz.

Azonnali segítség