# Jelszavak biztonságos tárolása PHP-ban: a password_hash helyes használata

> Jelszavak biztonságos tárolása PHP-ban password_hash-sel: bcrypt vagy Argon2id, költségtényező, a 72 bájtos határ és az átállás a régi MD5-hashekről.

Forrás: https://phpsos.de/hu/blog/passwoerter-in-php-speichern/  
Állapot: 2026. 10. 25.  
Szolgáltató: PHP SOS, PHP-vészhelyzeti segítség és szerverbiztonság. Azonnali segítség WhatsAppon: https://wa.me/491736494914?text=%C3%9Cdv%C3%B6zl%C3%B6m%2C%20PHP%20SOS%21%20Seg%C3%ADts%C3%A9gre%20van%20sz%C3%BCks%C3%A9g%C3%BCnk%20a%20PHP-szerver%C3%BCnkkel.%20C%C3%A9g%3A%20%E2%80%A6%20Weboldal%3A%20%E2%80%A6

**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
<?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
<?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
<?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?](https://phpsos.de/hu/php2shell/bin-ich-gehackt-anzeichen/) í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](https://phpsos.de/hu/ratgeber/brute-force-login-schutz/) ú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](https://phpsos.de/hu/blog/sichere-tokens-php/). További funkciókról áttekintést ad a [A PHP beépített biztonsági funkciói](https://phpsos.de/hu/php/eingebaute-sicherheitsfunktionen/).

## 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](https://phpsos.de/hu/leistungen/sicherheitsaudit-penetrationstest/) 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

- [PHP kézikönyv: password_hash](https://www.php.net/manual/de/function.password-hash.php)
- [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
