Aktuálna situácia: PHP2Shell. Dve kritické zraniteľnosti PHP (CVSS 9.2) umožňujú spustenie škodlivého kódu bez prihlásenia. Záplaty od 21. 10. 2026.Čo treba urobiť teraz →

Ochrana pred CSRF v aplikáciách PHP

Ako vývojári zabraňujú Cross-Site Request Forgery v aplikáciách PHP: tokeny pre každú požiadavku, ktorá niečo mení, kontrola pôvodu v hlavičke a cookies SameSite ako dodatočná vrstva.

Stav 5 min čítaniaBezpečný vývoj

Stručne: CSRF v PHP zabránite tak, že každá požiadavka, ktorá niečo mení, musí priniesť tajný token viazaný na reláciu, ktorý na serveri overíte pomocou hash_equals(). Dodatočne kontrolujete hlavičky Origin alebo Sec-Fetch-Site a cookies relácie nastavujete s SameSite. Požiadavky GET nikdy nesmú meniť údaje a ochranu potrebuje aj prihlasovací formulár.

Kliknutie, ktoré nikto nezbadá

Zamestnankyňa je prihlásená v backende obchodu a v druhej karte otvorí cudziu stránku. Táto stránka na pozadí odošle formulár do backendu, napríklad na zmenu e-mailovej adresy alebo založenie účtu. Prehliadač automaticky pripojí cookie relácie. Pre aplikáciu vyzerá požiadavka ako každá iná z vlastného tímu.

To je Cross-Site Request Forgery, skrátene CSRF: požiadavka, ktorú prihlásený používateľ nevedomky pošle aplikácii, ktorej dôveruje. Útočník odpoveď nevidí, ale ju ani nepotrebuje. Stačí, že sa akcia vykoná.

CSRF sa nedostáva do titulkov ako PHP2Shell, ale vo vlastnoručne vyvinutých aplikáciách PHP je to častý nález. Frameworky ako Symfony a Laravel prinášajú ochranu so sebou; medzery vznikajú tam, kde bola pre jednotlivé trasy vypnutá. Vlastné vývoje bez frameworku často nemajú žiadnu.

CSRF v PHP: ktoré požiadavky treba chrániť

Ochranu potrebujú všetky požiadavky, ktoré menia stav: ukladanie, mazanie, objednávanie, prideľovanie práv, zmena nastavení, nahrávanie súborov, odhlásenie. Čítacie volania token nepotrebujú, pokiaľ naozaj iba čítajú.

Z toho vyplýva prvé pravidlo: žiadna zmena cez GET. Odkazy ako loeschen.php?id=… sa dajú z cudzích stránok vyvolať obzvlášť ľahko, napríklad cez vložený obrázok. Akcie, ktoré menia, patria do POST, PUT, PATCH alebo DELETE.

Druhé pravidlo: chrániť aj prihlásenie. Pri takzvanom login CSRF je obeť nepozorovane prihlásená do účtu útočníka. Ak tam zadá platobné údaje alebo dokumenty, skončia u útočníka. Token v prihlasovacom formulári a nové ID relácie po úspešnom prihlásení tomu zabránia.

Vzor Synchronizer Token v PHP

Pre klasické aplikácie s reláciami odporúča OWASP vzor Synchronizer Token: server vytvorí náhodný token, uloží ho do relácie a očakáva ho späť v každom formulári, ktorý niečo mení. Dôležité je, aby sa token posielal vo formulári alebo vo vlastnej hlavičke, nie v 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') ?>">
    <!-- ďalšie polia -->
</form>

hash_equals() porovnáva v konštantnom čase, takže čas odpovede neprezradí nič o správnej hodnote. Po prihlásení by ste mali ID relácie obnoviť pomocou session_regenerate_id(true) a vytvoriť nový token. Prečo je random_bytes() správnym zdrojom a ktoré funkcie sú nevhodné, vysvetľuje Bezpečné náhodné čísla a tokeny v PHP.

Jeden token na reláciu pre väčšinu aplikácií stačí. Tokeny na formulár alebo na požiadavku ochranu trochu zvyšujú, vedú však k problémom s viacerými otvorenými kartami a tlačidlom Späť. Dôležitejšie než frekvencia zmeny je, aby sa token nikdy neobjavil v URL, kde môže skončiť v protokoloch, v histórii prehliadača a v údajoch referrer pre cudzie stránky.

Pre bezstavové aplikácie bez relácie uvádza OWASP ako alternatívu podpísané cookie Double Submit: token viazaný na reláciu pomocou HMAC. Jednoduchý, nepodpísaný variant sa výslovne neodporúča.

Druhá vrstva: Origin, Sec-Fetch-Site a SameSite

Moderné prehliadače posielajú pri požiadavkách informácie o svojom pôvode. Hlavička Origin uvádza volajúcu stránku, Sec-Fetch-Site hovorí, či požiadavka pochádza z tej istej stránky (same-origin), príbuznej (same-site) alebo cudzej (cross-site). Z toho sa dá zostaviť jednoduchá dodatočná kontrola:

<?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 pritom zdôrazňuje dva body: pôvod sa musí porovnávať úplne, aby neprešli podobne znejúce domény, a chýbajúca hlavička alebo hodnota null sa nesmie považovať za vlastný pôvod. Keďže staršie prehliadače hlavičky neposielajú vždy, hlavnou obranou zostáva token.

Treťou vrstvou sú cookies relácie s SameSite. PHP podporuje session.cookie_samesite od verzie 7.3, štandardná hodnota je prázdna. Nastavte aspoň Lax, pre čisté backendy je často možné Strict. Ostatné nastavenia cookies opisuje sprievodca Zabezpečenie relácií v PHP.

Ak používate CMS, zvyčajne prináša vlastné nástroje. WordPress napríklad pracuje s takzvanými nonce, ktoré pluginy zapájajú cez funkcie ako wp_nonce_field() a check_admin_referer(). Medzery v praxi vznikajú najmä v rozšíreniach, ktoré takéto kontroly pri jednotlivých akciách zabudnú. Preto skontrolujte najmä vlastnoručne napísané alebo málo rozšírené pluginy.

Pri rozhraniach, ktoré prehliadače používajú z iných domén, rozhoduje navyše konfigurácia CORS. Ak server vráti ako povolený každý pôvod požiadavky a zároveň povolí cookies, sám vyradí ochranu prehliadača. OWASP odporúča otvoriť CORS len pre výslovne dôveryhodné pôvody; plošné povolenie všetkých subdomén sa stane problémom, hneď ako sa niektorá z nich dostane do cudzích rúk.

Kontrolný zoznam pre existujúce aplikácie

Pri prerastených projektoch pomáha systematické prehliadnutie:

  1. Zachytiť všetky trasy a skripty, ktoré menia údaje, aj koncové body Ajax a nahrávanie súborov.
  2. Skontrolovať, či sa na to používa GET, a prestaviť na POST alebo vhodné metódy.
  3. Pre každú trasu, ktorá niečo mení, preukázať, že sa token overuje; výnimky vo frameworku hľadať cielene.
  4. Prihlásenie, odhlásenie a zmenu hesla otestovať osobitne.
  5. Doplniť session.cookie_samesite a kontrolu pôvodu.
  6. Odstrániť zraniteľnosti XSS, pretože votrelecký kód môže čítať každý token. Postup opisuje Ako zabrániť Cross-Site Scripting v PHP.
Dôležité

Ochrana pred CSRF, ktorá sa kontroluje len vo frontende cez JavaScript, je neúčinná. Kontrola sa musí uskutočniť na serveri skôr, než sa akcia vykoná.

Ako konkrétne pomáha PHP SOS?

  • Zachytíme všetky trasy vašej aplikácie PHP, ktoré niečo menia, a skontrolujeme, kde token chýba alebo bol vypnutý.
  • Zabudujeme centrálny kontrolný bod namiesto rozptýlených kontrol tokenov po mnohých skriptoch.
  • Doplníme kontrolu pôvodu a nastavenia SameSite bez rušenia platobných alebo prihlasovacích postupov.
  • Po prestavbe znova otestujeme a výsledky zdokumentujeme.

Úplnú kontrolu vašej aplikácie opisuje služba Bezpečnostný audit a penetračný test.

Časté otázky

Stačí SameSite=Lax ako ochrana pred CSRF?

Nie. Cookies SameSite sú podľa OWASP dodatočná vrstva, nie náhrada. Lax naďalej posiela cookies pri bežných zobrazeniach stránok cez GET a útoky zo subdomén toho istého webu nepokrýva.

Potrebujú API JSON token CSRF?

Ak sa API overuje pomocou cookies, áno, alebo rovnocennú kontrolu. Alternatívou sú vlastné hlavičky požiadavky, ktoré prehliadače pri cudzích stránkach povolia až po predbežnej kontrole CORS. Povolenie CORS potom smie obsahovať len výslovne dôveryhodné pôvody.

Musí byť chránený aj prihlasovací formulár?

Áno. Pri login CSRF je obeť nepozorovane prihlásená do cudzieho účtu a zadáva tam vlastné údaje. Token v prihlasovacom formulári a nová relácia po prihlásení tomu zabránia.

Chráni ochrana pred CSRF aj pred XSS?

Naopak: zraniteľnosť XSS vyradí z funkcie každú ochranu pred CSRF, pretože votrelecký kód môže v mene stránky čítať platné tokeny a posielať ich so sebou. Obe slabiny sa musia odstraňovať oddelene.

Zdroje

Okamžitý kontakt

Každá hodina sa počíta. Napíšte nám hneď.

Stručne opíšte systém, verziu PHP a svoje pozorovanie. Ozveme sa, vyjasníme situáciu a budeme pracovať na diaľku, kým nebude incident uzavretý a zdokumentovaný.

Okamžitá pomoc