Pe scurt: PHP oferă pentru cele mai frecvente sarcini de securitate funcții gata făcute și verificate: password_hash() pentru parole, random_bytes() și random_int() pentru token-uri, htmlspecialchars() împotriva cross-site scripting, interogări pregătite cu PDO împotriva SQL injection, hash_equals() pentru comparații sigure și extensia Sodium pentru criptografie. Cine folosește consecvent aceste elemente evită cele mai multe vulnerabilități de aplicație. Împotriva erorilor din interpretorul PHP însuși, ca la PHP2Shell, ele nu ajută; acolo ajută doar actualizarea.
De ce funcții de securitate PHP integrate?
Scrierea proprie a codului de securitate este predispusă la erori. Un hash de parolă propriu, un generator de token-uri construit în casă sau un filtru improvizat pentru ieșirile HTML par adesea corecte, fără să fie. Funcțiile integrate sunt documentate, testate și întreținute prin actualizările PHP.
Pentru factorii de decizie, aceasta înseamnă: nu întrebați agenția sau echipa de dezvoltare dacă funcțiile de securitate au fost construite singure, ci dacă se folosesc funcțiile standard ale limbajului. Tabelul oferă o privire de ansamblu.
| Sarcină | Funcție | Disponibilă din | Observație importantă |
|---|---|---|---|
| Stocarea parolelor | password_hash(), password_verify() |
PHP 5.5 | coloană până la 255 de caractere; bcrypt trunchiază la 72 de octeți |
| Token-uri aleatorii | random_bytes(), random_int() |
PHP 7.0 | niciodată rand() sau mt_rand() pentru secrete |
| Aleatoriu orientat pe obiecte | Random\Randomizer |
PHP 8.2 | aceeași siguranță, interfață mai flexibilă |
| Mascarea ieșirii HTML | htmlspecialchars() |
dintotdeauna | flag-urile implicite din 8.1 maschează și ghilimelele simple |
| Comparație în timp constant | hash_equals() |
PHP 5.6 | datele introduse de utilizator ca al doilea argument |
| Criptografie modernă | Sodium (sodium_*) |
PHP 7.2 | în loc de criptare proprie |
| Secrete în stacktrace-uri | #[\SensitiveParameter] |
PHP 8.2 | valoarea nu apare în trace |
| Verificarea datelor de intrare | filter_var() |
PHP 5.2 | verifică formatul, nu înlocuiește mascarea |
Parole și token-uri
password_hash() generează un hash cu salt, password_verify() îl verifică. Cu PASSWORD_DEFAULT, PHP folosește în prezent bcrypt; din PHP 8.4, factorul de cost implicit este, potrivit manualului, 12 în loc de 10. Deoarece algoritmul implicit se poate schimba, manualul recomandă o coloană de bază de date cu 255 de caractere. La bcrypt, parolele sunt tăiate după 72 de octeți, lucru de luat în seamă la frazele-parolă foarte lungi.
<?php
// Înregistrare
$hash = password_hash($passwort, PASSWORD_DEFAULT);
// Autentificare, inclusiv actualizarea automată a hash-urilor vechi
if (password_verify($eingabe, $hash)) {
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($eingabe, PASSWORD_DEFAULT); // salvează din nou
}
}
// Token pentru un link de resetare a parolei
$token = bin2hex(random_bytes(32));
Pentru compararea secretelor, de exemplu a unei semnături, trebuie folosit hash_equals(). O comparație obișnuită cu === poate dezvălui, potrivit manualului, prin durata de execuție, de la ce poziție diferă două valori. Mai detaliat: Stocarea sigură a parolelor în PHP și numere aleatorii și token-uri sigure.
Mascarea ieșirilor și interogarea sigură a bazei de date
Cross-site scripting apare atunci când datele introduse de utilizator ajung nefiltrate în HTML. htmlspecialchars() convertește caracterele speciale în entități HTML. Din PHP 8.1, flag-urile implicite sunt ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401; înainte, ghilimelele simple nu erau convertite. Cine trebuie să accepte versiuni mai vechi indică explicit flag-urile.
SQL injection este prevenit de interogările pregătite. Valorile sunt transmise separat de textul SQL și nu pot modifica interogarea:
<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();
echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');
Detaliile se găsesc la Prevenirea cross-site scripting în PHP și în pagina despre SQL injection.
Verificarea datelor de intrare este un al doilea pas, separat. filter_var() stabilește dacă o valoare are un format valid, de exemplu o adresă de e-mail sau un număr întreg într-un interval permis. Aceasta nu înlocuiește însă mascarea la ieșire și nici o interogare pregătită, deoarece și valorile valide formal pot conține caractere speciale.
Ținerea secretelor departe de mesajele de eroare
O scurgere de date subestimată sunt stacktrace-urile. Dacă într-o funcție apare o eroare, PHP înregistrează lanțul de apeluri împreună cu argumentele. Dacă acolo se află o parolă sau o cheie API, ea ajunge în log. Din PHP 8.2, atributul #[\SensitiveParameter] marchează astfel de parametri; valoarea lor apare atunci în trace doar ca obiect SensitiveParameterValue.
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
// ... verificare ...
throw new RuntimeException('Datenbank nicht erreichbar');
}
Potrivit unei observații din manual, atributul acționează doar la implementarea concretă, nu la metoda unei interfețe. Setați-l de aceea acolo unde codul rulează efectiv.
Sesiuni: setări sigure și valori implicite noi
Sesiunile sunt o țintă frecventă de atac. Trei setări sunt centrale: session.use_strict_mode=1 respinge ID-urile de sesiune pe care serverul nu le-a generat singur; session.cookie_httponly=1 împiedică accesul prin JavaScript la cookie-ul de sesiune; session.cookie_samesite=Lax îngreunează trimiterea lui împreună cu cererile de pe site-uri străine. Potrivit RFC-ului adoptat, exact aceste trei valori devin implicite cu PHP 8.6. Setați-le singuri până atunci, iar și după aceea în mod explicit, pentru ca configurația să nu depindă de valoarea implicită.
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
Mai multe la Securizarea sesiunilor în PHP.
Ce nu realizează funcțiile integrate
Proiectul PHP este clar în politica sa de securitate: PHP nu este un sandbox. Ocolirile open_basedir sau disable_functions, datele rău intenționate transmise lui unserialize() și argumentele neverificate transmise unor funcții precum mysqli_query() nu sunt considerate vulnerabilități ale PHP. Pentru operatori, aceasta înseamnă: aceste setări sunt o întărire utilă, dar nu o graniță de securitate, iar unserialize() nu are ce căuta cu date străine.
Al doilea punct privește PHP2Shell. CVE-2026-109618 și CVE-2026-109619 permit, potrivit php.net, execuție de cod înainte sau în timp ce rulează aplicația dumneavoastră; la mod_php a fost demonstrat un exploit înainte ca vreun cod al aplicației să fie executat. Nicio funcție din codul dumneavoastră nu poate intercepta aceasta. Programarea sigură și o versiune PHP actuală sunt două obligații separate, iar ambele trebuie îndeplinite.
Cum ajută PHP SOS concret?
În auditul de securitate pentru aplicații PHP verificăm țintit:
- Gestionarea parolelor și a token-urilor: Se folosesc
password_hash()șirandom_bytes(), sau există construcții proprii? - Ieșiri și interogări: Unde ajung datele de intrare nefiltrate în HTML, SQL sau comenzi shell?
- Configurarea sesiunilor: Sunt setate Strict Mode, HttpOnly, SameSite și Secure și nu pot fi suprascrise?
- Mediul de execuție: Rulează o versiune PHP acceptată, cu remedierile din 21.10.2026?
Întrebări frecvente
Cum se stochează corect parolele în PHP?
Cu password_hash() și PASSWORD_DEFAULT, iar verificarea se face cu password_verify(). Potrivit manualului, coloana din baza de date ar trebui să poată conține până la 255 de caractere, deoarece algoritmul implicit se poate schimba în viitor.
Este rand() potrivit pentru token-uri?
Nu. Pentru token-uri, chei și linkuri de resetare a parolei trebuie folosite random_bytes() sau random_int(). Potrivit manualului, acestea oferă valori aleatorii sigure din punct de vedere criptografic.
De când este inclus Sodium în PHP?
Extensia Sodium pentru criptografie modernă face parte din PHP începând cu PHP 7.2.0. Versiunile mai vechi o puteau adăuga ulterior doar prin PECL.
Protejează aceste funcții împotriva PHP2Shell?
Nu. Ele protejează împotriva erorilor din aplicația dumneavoastră. PHP2Shell se află în interpretorul însuși și se închide doar printr-o actualizare PHP, urmată de repornirea tuturor proceselor PHP.
Se schimbă valorile implicite ale sesiunilor în PHP 8.6?
Da, potrivit RFC-ului adoptat, session.use_strict_mode și session.cookie_httponly se activează implicit, iar session.cookie_samesite se setează pe Lax. Configurațiile existente ar trebui totuși să le setați singuri în mod explicit.