# Biztonságos véletlenszámok és tokenek PHP-ban a random_bytes-szal

> Biztonságos tokenek létrehozása PHP-ban random_bytes és random_int segítségével: hossz, kódolás, tárolás hashként, lejárati idő és kerülendő függvények.

Forrás: https://phpsos.de/hu/blog/sichere-tokens-php/  
Á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:** Biztonságos tokeneket PHP-ban a `random_bytes()` függvénnyel hoz létre, például 32 bájtot, amelyet a `bin2hex()` vagy a Base64-URL segítségével alakít szöveggé. Egy tartományba eső véletlenszámokhoz a `random_int()` való, rögzített karakterkészletből álló kódokhoz a PHP 8.3 óta a `Random\Randomizer::getBytesFromString()`. A tokeneket hashként tárolja, érvényességüket korlátozza, csak egyszer használja őket, és a `hash_equals()` függvénnyel hasonlítja össze.

## Egy link, amelyet túl könnyű kitalálni

„Elfelejtette a jelszavát?” Egy kattintás, és a rendszer elküld egy linket egy hosszú kóddal. Aki ismeri a linket, beállíthatja a jelszót. Éppen ezért ennek a kódnak megjósolhatatlannak kell lennie. Ha nem az, a támadónak sem a postafiókra, sem a régi jelszóra nincs szüksége, csak elég próbálkozásra.

A PHP-alkalmazások ellenőrzései során meglepően gyakran találni olyan tokeneket, amelyeket az időből, a felhasználói azonosítóból vagy egy egyszerű véletlenszám-generátorból építettek. Hosszúnak és véletlennek látszanak, de nem azok. Ugyanez érvényes az API-kulcsokra, a meghívó linkekre, a dokumentumok megosztási linkjeire, a megerősítő kódokra és a CSRF-tokenekre.

A kockázat kézzelfogható: egy megjósolható visszaállító link lehetővé teszi minden olyan fiók átvételét, amelynek az e-mail-címe ismert, anélkül hogy a tulajdonos bármit észrevenne, amíg maga nem tud többé bejelentkezni.

A PHP a 7.0-s verzió óta egyszerű és biztonságos megoldást kínál. Csak következetesen kell használni.

## random_bytes PHP-ban: honnan származnak a biztonságos véletlenértékek

A `random_bytes()` a PHP kézikönyve szerint kriptográfiailag biztonságos véletlenbájtokat szolgáltat, amelyek hosszú életű titkokhoz, például kulcsokhoz is alkalmasak. A függvény az operációs rendszer véletlenforrását használja, Linuxon például a `getrandom()` hívást, Windowson a CNG-interfészt. Ha nem talál megfelelő forrást, a PHP 8.2 óta `Random\RandomException` kivételt dob.

Az áttekintés megmutatja, mely függvények alkalmasak titkokhoz:

| Függvény | Alkalmas tokenekhez? | Megjegyzés |
|---|---|---|
| `random_bytes()` | igen | biztonságos bájtok, a PHP 7.0 óta |
| `random_int()` | igen | biztonságos szám egy tartományban, a PHP 7.0 óta |
| `Random\Randomizer` Secure engine-nel | igen | a kézikönyv szerint a Secure az alapértelmezett engine |
| `rand()`, `mt_rand()` | nem | megjósolható, csak nem biztonsági célokra |
| `uniqid()` | nem | idő alapú, egyediségre való |
| `md5(time())`, `sha1($id)` | nem | a bemenet kitalálható, a hash ezen nem változtat |
| `str_shuffle()`, `array_rand()` | nem | nem használnak biztonságos generátort |

## Tokenek létrehozása: hossz és kódolás

32 véletlen bájt 256 bitnek felel meg, és szinte minden célra bőven elég. Linkekben vagy fejlécekben való átvitelhez a tokent szöveggé kell alakítani. Két változat elterjedt:

```php
<?php
declare(strict_types=1);

// Hexa: 64 karakter, csak 0-9 és a-f
$tokenHex = bin2hex(random_bytes(32));

// Base64-URL: 43 karakter, további kódolás nélkül biztonságos URL-ekben
$tokenUrl = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');

// Véletlenszám egy tartományban, például egy kiválasztáshoz
$index = random_int(0, 9);

// A PHP 8.3-tól: hatjegyű számkód, pl. SMS-es megerősítéshez
$randomizer = new \Random\Randomizer();
$code = $randomizer->getBytesFromString('0123456789', 6);
```

A rövid számkódok csak akkor vállalhatók, ha a próbálkozások száma szigorúan korlátozott, és a kód néhány perc után lejár. Az e-mailben küldött linkekhez mindig a hosszú tokent használja.

A partnerek vagy saját rendszerek által tartósan használt API-kulcsokhoz két kiegészítés vált be. Egy rövid, nem titkos előtag a véletlen rész előtt, például a környezetre vagy a célra utalva, megkönnyíti a felismerést a naplókban és a kódtárakban való megtalálásnál. A kulcsot pedig csak egyszer, a létrehozáskor jelenítik meg; utána a rendszer már csak a hasht ismeri. Ha egy kulcs elvész, kicserélik, nem állítják helyre.

Óvatosan a saját építésű tokenekkel, amelyek információt tartalmaznak, például a felhasználói azonosítót és a lejárati időt Base64-ben. A kódolás nem védelem: ezeket a tokeneket bárki elolvashatja és módosíthatja. Ha egy tokennek adatot kell hordoznia, titkos kulccsal alá kell írni, például a `hash_hmac('sha256', ...)` segítségével, az aláírást pedig a `hash_equals()` függvénnyel ellenőrzik. Bonyolultabb esetekben az ellenőrzött könyvtárak előnyben részesítendők a saját konstrukciókkal szemben.

## Tokenek tárolása, ellenőrzése és lejárata

Egy biztonságosan létrehozott token csak a munka fele. Legalább ilyen fontos, hogyan bánik vele az alkalmazás. Egy bevált eljárás visszaállító és meghívó linkekhez:

1. **Csak a hasht tárolni:** az adatbázisban a `hash('sha256', $token)` áll, maga a token csak linken keresztül jut el a felhasználóhoz.
2. **Az érvényességet korlátozni:** a lejárati időt is tárolni, és beváltáskor ellenőrizni.
3. **Egyszer használni:** sikeres használat után a bejegyzést törölni vagy felhasználtként jelölni.
4. **Változásoknál érvényteleníteni:** jelszómódosítás után a fiók összes nyitott visszaállító tokenjét törölni.
5. **Állandó időben összehasonlítani:** ahol egy tokent közvetlenül egy tárolt értékkel hasonlítanak, a `hash_equals()`-t használni, a tárolt értékkel első paraméterként.

```php
<?php
// Létrehozás
$token = bin2hex(random_bytes(32));
$eintrag = [
    'konto_id'   => $kontoId,
    'token_hash' => hash('sha256', $token),
    'gueltig_bis'=> (new DateTimeImmutable('+30 minutes'))->format('Y-m-d H:i:s'),
];
// A $token-t csak a linkben elküldeni, az $eintrag-ot tárolni

// Beváltás
$gesucht = hash('sha256', (string) ($_GET['token'] ?? ''));
// A bejegyzést prepared statementtel a token_hash alapján keresni,
// lejáratot ellenőrizni, utána a bejegyzést azonnal törölni
```

Korlátozza ezenkívül a visszaállítási kérések számát fiókonként és időszakonként, hogy a funkcióval ne lehessen tömeges e-mail-küldéssel visszaélni. A visszaállítási kérésre adott válasz ráadásul ne áruljon el, hogy a megadott címhez egyáltalán tartozik-e fiók.

Egy gyors hash, mint az SHA-256, itt elég, mert maga a token már hosszú és véletlen. Az emberek által választott jelszavakra ez nem érvényes; ott lassú eljárások kellenek, ahogyan a [Jelszavak biztonságos tárolása PHP-ban](https://phpsos.de/hu/blog/passwoerter-in-php-speichern/) elmagyarázza.

> **Tipp:**
> A tokenek nem valók naplófájlokba. Ellenőrizze, hogy a webszervere naplózza-e a lekérdezési paraméterekkel ellátott teljes URL-eket, és hogy a hibajelentések küldenek-e kéréseket tartalmazó adatokat.

## Egy incidens után: tokenek és kulcsok megújítása

Aki kódot tudott végrehajtani egy szerveren, annak általában a tárolt tokenekhez, API-kulcsokhoz és munkamenet-adatokhoz is volt hozzáférése. Ha a PHP2Shell után vagy más incidens miatt betörés gyanúja áll fenn, ezért ne csak a jelszavakat, hanem a hosszú életű tokeneket és kulcsokat is újítsa meg: API-hozzáféréseket, a sütik vagy linkek aláíró kulcsait, a fizetési és szállítási szolgáltatások hozzáféréseit.

A sessionök különleges eset: a PHP maga hozza létre a session-azonosítókat. Hogyan biztosíthatja a beállításaikat, és hogyan szüntetheti meg a sessionöket egy incidens után, azt az [A sessionök biztonságossá tétele PHP-ban](https://phpsos.de/hu/ratgeber/session-sicherheit-php/) útmutató írja le. A hamisított kérések elleni űrlaptokenekről lásd a [CSRF-védelem PHP-alkalmazásokban](https://phpsos.de/hu/blog/csrf-schutz-php/) cikket. További beépített eszközöket mutat be 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?

- Megkeressük az alkalmazásában az összes helyet, ahol tokeneket, kódokat és kulcsokat hoznak létre, és kicseréljük a nem biztonságos forrásokat.
- Ellenőrizzük a visszaállító, meghívó és megosztási linkek tárolását, lejáratát és egyszeri használatát.
- Gondoskodunk arról, hogy a tokenek ne kerüljenek naplókba, hibajelentésekbe vagy elemző eszközökbe.
- Egy incidens után Önnel együtt megtervezzük a tokenek és kulcsok rendezett cseréjét.

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

**Miért alkalmatlan az mt_rand tokenekhez?**  
Az mt_rand és a rand statisztikához és játékokhoz való, nem titkokhoz. A kimeneteik adott körülmények között megjósolhatók. Mindenre, amit a támadó nem találhat ki, a random_bytes-t vagy a random_int-et használja.

**Milyen hosszú legyen egy token?**  
Jelszó-visszaállító linkekhez, meghívókhoz vagy API-kulcsokhoz 32 véletlen bájt szilárd választás, hexa szövegként 64 karakter. A 16 bájt, vagyis 128 bit elterjedt alsó határ.

**A uniqid biztonságos token?**  
Nem. A uniqid az aktuális időn alapul, és egyediségre való, nem titoktartásra. Az olyan kombinációk is megjósolhatók, mint az idő vagy a felhasználói azonosító md5-je.

**Titkosítanom kell az adatbázisban a visszaállító tokeneket?**  
A token helyett annak hasht tárolja, például SHA-256-tal. Aki az adatbázist olvassa, ezzel nem tud érvényes linkeket építeni. Mivel maga a token már hosszú és véletlen, nincs szükség lassú eljárásra, mint a jelszavaknál.

**Mi történik, ha a rendszer nem talál véletlenforrást?**  
A random_bytes és a random_int a PHP 8.2 óta Random\RandomException kivételt dob. Kapja el ezt az esetet, és szakítsa meg a folyamatot, ahelyett hogy gyengébb forrásra térne át.

## Források

- [PHP kézikönyv: random_bytes](https://www.php.net/manual/de/function.random-bytes.php)
- [PHP kézikönyv: Random\Randomizer::getBytesFromString](https://www.php.net/manual/de/random-randomizer.getbytesfromstring.php)
- [PHP kézikönyv: hash_equals](https://www.php.net/manual/de/function.hash-equals.php)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
