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 →

Biztonságos véletlenszámok és tokenek PHP-ban a random_bytes-szal

Hogyan hoznak létre a fejlesztők PHP-ban tokeneket jelszó-visszaállító linkekhez, API-kulcsokhoz és egyszeri kódokhoz: kriptográfiailag biztonságos források, elegendő hossz, tárolás hashként és korlátozott érvényesség.

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

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.

„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
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
// 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 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 útmutató írja le. A hamisított kérések elleni űrlaptokenekről lásd a CSRF-védelem PHP-alkalmazásokban cikket. További beépített eszközöket mutat be a A PHP beépített biztonsági funkciói.

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 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

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