Situația actuală: PHP2Shell. Două vulnerabilități critice PHP (CVSS 9.2) permit cod malițios fără autentificare. Patchuri din 21.10.2026.Ce este de făcut acum →

Protecția CSRF în aplicațiile PHP

Cum previn dezvoltatorii Cross-Site Request Forgery în aplicațiile PHP: token-uri pentru fiecare cerere care modifică ceva, verificarea originii în antet și cookie-uri SameSite ca strat suplimentar.

Stadiu 6 min de cititDezvoltare sigură

Pe scurt: Preveniți CSRF în PHP cerând ca fiecare cerere care modifică ceva să aducă un token secret, legat de sesiune, pe care îl verificați pe server cu hash_equals(). În plus verificați antetele Origin sau Sec-Fetch-Site și setați cookie-urile de sesiune cu SameSite. Cererile GET nu au voie să modifice niciodată date, iar formularul de login are nevoie, la rândul său, de protecție.

Un clic pe care nu-l observă nimeni

O angajată este autentificată în backend-ul magazinului și deschide într-o a doua filă un site străin. Acest site trimite pe fundal un formular către backend, de exemplu pentru schimbarea unei adrese de e-mail sau crearea unui cont. Browserul atașează automat cookie-ul de sesiune. Pentru aplicație, cererea arată ca oricare alta din propria echipă.

Aceasta este Cross-Site Request Forgery, pe scurt CSRF: o cerere pe care un utilizator autentificat o trimite, fără să știe, unei aplicații în care are încredere. Atacatorul nu vede răspunsul, dar nici nu are nevoie de el. Este suficient ca acțiunea să fie executată.

CSRF nu apare în titluri ca PHP2Shell, dar este o constatare frecventă în aplicațiile PHP dezvoltate propriu. Framework-uri precum Symfony și Laravel aduc o protecție; vulnerabilitățile apar acolo mai ales unde ea a fost dezactivată pentru anumite rute. Dezvoltările proprii fără framework nu au adesea deloc una.

CSRF în PHP: ce cereri trebuie protejate

Protecție au nevoie toate cererile care modifică o stare: salvare, ștergere, comandă, acordarea de drepturi, modificarea setărilor, încărcarea de fișiere, deconectarea. Apelurile de citire nu au nevoie de token, atâta timp cât chiar doar citesc.

De aici rezultă prima regulă: nicio modificare prin GET. Linkuri precum loeschen.php?id=… pot fi declanșate deosebit de ușor de site-uri străine, de exemplu printr-o imagine încorporată. Acțiunile care modifică aparțin în POST, PUT, PATCH sau DELETE.

A doua regulă: protejați și autentificarea. La așa-numitul login CSRF, o victimă este autentificată pe nesimțite într-un cont al atacatorului. Dacă introduce acolo date de plată sau documente, acestea ajung la atacator. Un token în formularul de login și un nou ID de sesiune după o autentificare reușită previn acest lucru.

Modelul tokenului sincronizator în PHP

Pentru aplicațiile clasice cu sesiuni, OWASP recomandă modelul tokenului sincronizator: serverul generează un token aleatoriu, îl stochează în sesiune și îl așteaptă înapoi în fiecare formular care modifică ceva. Important este ca tokenul să fie trimis în formular sau într-un antet propriu, nu într-un cookie.

<?php
declare(strict_types=1);

function csrfToken(): string
{
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function csrfPruefen(): void
{
    $gesendet = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
    if (!is_string($gesendet) || !hash_equals(csrfToken(), $gesendet)) {
        http_response_code(403);
        exit('Anfrage abgelehnt.');
    }
}

if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
    csrfPruefen();
}
?>
<form method="post" action="/konto/email">
    <input type="hidden" name="csrf_token"
           value="<?= htmlspecialchars(csrfToken(), ENT_QUOTES, 'UTF-8') ?>">
    <!-- alte câmpuri -->
</form>

hash_equals() compară în timp constant, astfel încât timpul de răspuns nu trădează nimic despre valoarea corectă. După login ar trebui să reînnoiți ID-ul de sesiune cu session_regenerate_id(true) și să generați un token nou. De ce random_bytes() este sursa potrivită și ce funcții sunt nepotrivite explică Numere aleatorii și token-uri sigure în PHP.

Un token pe sesiune este suficient pentru majoritatea aplicațiilor. Token-urile pe formular sau pe cerere măresc puțin protecția, dar duc la probleme cu mai multe file deschise și cu butonul Înapoi. Mai important decât frecvența schimbării este ca tokenul să nu apară niciodată în URL-uri, unde poate ajunge în jurnale, în istoricul browserului și în informațiile Referrer către site-uri străine.

Pentru aplicațiile fără stare, fără sesiune, OWASP indică drept alternativă cookie-ul double-submit semnat: un token legat de sesiune prin HMAC. Varianta simplă, nesemnată, nu este recomandată în mod explicit.

Al doilea strat: Origin, Sec-Fetch-Site și SameSite

Browserele moderne trimit la cereri informații despre originea lor. Antetul Origin indică pagina apelantă, iar Sec-Fetch-Site spune dacă cererea provine de la aceeași pagină (same-origin), de la una înrudită (same-site) sau de la una străină (cross-site). De aici se poate construi o verificare suplimentară simplă:

<?php
$erlaubteHerkunft = 'https://www.example.de';
$fetchSite = $_SERVER['HTTP_SEC_FETCH_SITE'] ?? null;
$origin    = $_SERVER['HTTP_ORIGIN'] ?? null;

$verdaechtig = ($fetchSite !== null && $fetchSite !== 'same-origin')
    || ($fetchSite === null && $origin !== null && $origin !== $erlaubteHerkunft);

if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $verdaechtig) {
    http_response_code(403);
    exit;
}

OWASP subliniază două aspecte: originea trebuie comparată integral, pentru ca domeniile cu sunet asemănător să nu treacă, iar un antet lipsă sau valoarea null nu are voie să fie considerată origine proprie. Deoarece browserele mai vechi nu trimit întotdeauna antetele, tokenul rămâne apărarea principală.

Al treilea strat sunt cookie-urile de sesiune cu SameSite. PHP acceptă session.cookie_samesite începând cu versiunea 7.3, valoarea implicită este goală. Setați cel puțin Lax; pentru backend-uri pure, Strict este adesea posibil. Celelalte setări ale cookie-urilor le descrie ghidul Securizarea sesiunilor în PHP.

Dacă folosiți un CMS, acesta aduce de regulă instrumente proprii. WordPress, de exemplu, lucrează cu așa-numitele nonce-uri, pe care pluginurile le integrează prin funcții precum wp_nonce_field() și check_admin_referer(). Vulnerabilitățile apar în practică mai ales în extensii care uită asemenea verificări la anumite acțiuni. Verificați de aceea cu atenție în special pluginurile scrise de dumneavoastră sau puțin răspândite.

La interfețele pe care browserele le folosesc de pe alte domenii, decide suplimentar configurarea CORS. Dacă serverul returnează orice origine solicitantă ca permisă și permite în același timp cookie-uri, el anulează el însuși protecția browserului. OWASP recomandă deschiderea CORS doar pentru origini declarate explicit de încredere; o permisiune globală pentru toate subdomeniile devine o problemă de îndată ce unul dintre ele ajunge pe mâini străine.

Listă de verificare pentru aplicațiile existente

La proiectele crescute în timp ajută o trecere în revistă sistematică:

  1. Inventariați toate rutele și scripturile care modifică date, inclusiv endpoint-urile Ajax și upload-urile de fișiere.
  2. Verificați dacă pentru ele se folosește GET și treceți-le la POST sau la metode potrivite.
  3. Pentru fiecare rută care modifică ceva, demonstrați că un token este verificat; căutați în mod țintit excepțiile din framework.
  4. Testați separat autentificarea, deconectarea și schimbarea parolei.
  5. Completați session.cookie_samesite și verificarea originii.
  6. Remediați vulnerabilitățile XSS, deoarece codul introdus pe ascuns poate citi orice token. Procedura o descrie Prevenirea Cross-Site Scripting în PHP.
Important

O protecție CSRF verificată doar în frontend, prin JavaScript, este ineficientă. Verificarea trebuie să aibă loc pe server, înainte ca acțiunea să fie executată.

Cum ajută PHP SOS concret?

  • Inventariem toate rutele care modifică ceva în aplicația dumneavoastră PHP și verificăm unde lipsește un token sau a fost dezactivat.
  • Introducem un punct central de verificare, în loc să distribuim verificările de token în multe scripturi.
  • Completăm verificarea originii și setările SameSite, fără a perturba fluxurile de plată sau de login.
  • Testăm din nou după schimbare și documentăm rezultatele.

O verificare completă a aplicației dumneavoastră descrie serviciul Audit de securitate și test de penetrare.

Întrebări frecvente

Este suficient SameSite=Lax ca protecție CSRF?

Nu. Potrivit OWASP, cookie-urile SameSite sunt un strat suplimentar, nu un înlocuitor. Lax trimite în continuare cookie-uri la accesările obișnuite de pagini prin GET, iar atacurile din subdomenii ale aceluiași site nu sunt acoperite.

Au nevoie API-urile JSON de un token CSRF?

Dacă API-ul se autentifică cu cookie-uri, da, sau de o verificare echivalentă. O alternativă sunt antetele de cerere proprii, pe care browserele le permit pentru site-uri străine doar după o verificare prealabilă CORS. Atunci însă permisiunea CORS trebuie să conțină doar origini declarate explicit de încredere.

Trebuie protejat și formularul de login?

Da. La login CSRF, o victimă este autentificată pe nesimțite într-un cont străin și introduce acolo propriile date. Un token în formularul de login și o sesiune nouă după autentificare previn acest lucru.

Protejează protecția CSRF și împotriva XSS?

Invers: o vulnerabilitate XSS anulează orice protecție CSRF, deoarece codul introdus pe ascuns poate citi, în numele paginii, token-uri valide și le poate trimite odată cu cererea. Ambele vulnerabilități trebuie remediate separat.

Surse

Contact imediat

Fiecare oră contează. Scrieți-ne acum.

Descrieți pe scurt sistemul, versiunea PHP și ce ați observat. Ne vom face auziți, clarificăm situația și lucrăm la distanță până când incidentul este încheiat și documentat.

Ajutor imediat