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 →

Validácia a filtrovanie vstupov v PHP pomocou filter_var

Ako vývojári kontrolujú vstupy v PHP pomocou filter_var, filter_input_array a zoznamov povolených hodnôt, ktoré filtre sú zastarané a prečo validácia nenahrádza Prepared Statements ani kódovanie výstupu.

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

Stručne: Vstupy v PHP validujete pomocou filter_var() alebo filter_input_array() a jasných pravidiel pre každé pole: typ, rozsah, dĺžka a povolené hodnoty. Čo nesedí, sa odmietne, nie mlčky prerobí. Validácia je dôležitá pre čisté údaje a menšiu útočnú plochu, nenahrádza však ani Prepared Statements proti SQL injection, ani kódovanie primerané kontextu proti XSS.

Prečo „filtrovať všetko“ nie je koncepcia

V mnohých starších projektoch PHP nájdete na začiatku každého súboru cyklus, ktorý posiela všetky hodnoty z $_GET a $_POST cez čistiacu funkciu. Pôsobí to bezpečne. V praxi to raz odstráni priveľa, napríklad apostrofy v priezviskách, raz primálo, pretože tá istá funkcia má platiť naraz pre SQL, HTML a názvy súborov.

Zmysluplná validácia funguje inak: pre každé pole sa pýta, čo je tam dovolené. Objednané množstvo je celé číslo od 1 po hornú hranicu. Pole zoradenia je jedna z troch pevných hodnôt. Dátum má určitý formát a leží pred iným dátumom alebo po ňom. Všetko ostatné sa odmietne.

OWASP pritom rozlišuje dve úrovne: syntaktickú kontrolu, či má hodnota správny tvar, a sémantickú kontrolu, či dáva v súvislosti zmysel. Obe patria na server; kontroly v prehliadači slúžia len na pohodlné ovládanie.

Ktoré filtre PHP prináša

Rozšírenie Filter je v PHP štandardne obsiahnuté. Najdôležitejšie validačné filtre podľa príručky PHP:

Filter Kontroluje Dôležité možnosti a poznámky
FILTER_VALIDATE_INT celé číslo min_range, max_range
FILTER_VALIDATE_FLOAT desatinné číslo decimal pre oddeľovač
FILTER_VALIDATE_BOOL pravdivostná hodnota s FILTER_NULL_ON_FAILURE rozlíšiteľná od „nepravda“
FILTER_VALIDATE_EMAIL tvar e-mailovej adresy nedokazuje, že schránka existuje
FILTER_VALIDATE_URL tvar URL schému kontrolovať samostatne, žiadne internacionalizované domény
FILTER_VALIDATE_IP adresa IP príznaky pre súkromné a rezervované rozsahy
FILTER_VALIDATE_REGEXP vlastný vzor vzor ukotviť pomocou ^ a $

Čistiaci filter FILTER_SANITIZE_STRING je od PHP 8.1 zastaraný. Kto ho ešte používa, mal by validáciu prestaviť na vhodné filtre a pre výstup použiť htmlspecialchars().

filter_var v PHP: poriadna kontrola formulára

Pomocou filter_input_array() sa dá celý formulár skontrolovať jedným krokom voči definícii. Neznáme polia sa pritom neprevezmú:

<?php
declare(strict_types=1);

$regeln = [
    'menge'   => ['filter' => FILTER_VALIDATE_INT,
                  'options' => ['min_range' => 1, 'max_range' => 50]],
    'email'   => FILTER_VALIDATE_EMAIL,
    'agb'     => ['filter' => FILTER_VALIDATE_BOOL, 'flags' => FILTER_NULL_ON_FAILURE],
    'versand' => ['filter' => FILTER_VALIDATE_REGEXP,
                  'options' => ['regexp' => '/^(standard|express)$/']],
];

$daten  = filter_input_array(INPUT_POST, $regeln) ?? [];
$fehler = [];

foreach ($regeln as $feld => $_) {
    if (!array_key_exists($feld, $daten) || $daten[$feld] === false || $daten[$feld] === null) {
        $fehler[] = $feld;
    }
}

if ($fehler !== []) {
    http_response_code(422);
    // vypísať chybové hlásenie pre každé pole, vstupy nespracovať
}

Všimnite si striktné porovnania pomocou ===: platná hodnota 0 alebo prázdny reťazec sa nesmie zamieňať s neúspechom. Prečo sú tu voľné porovnania nebezpečné, vysvetľuje Type Juggling: voľné porovnania ako bezpečnostné riziko. Ako PHP vôbec sprístupňuje údaje požiadavky, opisuje Superglobals: $_GET, $_POST, $_FILES a spol..

Nástrahy pri e-maile, URL a voľných textoch

Niektoré filtre robia menej, než by naznačoval ich názov:

  1. URL: FILTER_VALIDATE_URL akceptuje aj iné schémy než http a https. Schému potom skontrolujte pomocou parse_url() voči pevnému zoznamu. Ak sa URL sťahuje zo servera, platia dodatočné pravidlá, pozri Ako zabrániť Server-Side Request Forgery v PHP.
  2. E-mailové adresy: filter kontroluje tvar, nie vlastníctvo. Kto si musí byť istý, pošle potvrdzovací odkaz.
  3. Voľný text: mená, správy a adresy sa dajú len ťažko zmysluplne obmedziť na znaky. Kontrolujte dĺžku a kódovanie znakov, napríklad pomocou mb_check_encoding($wert, 'UTF-8'), a pri výstupe sa spoliehajte na kódovanie.
  4. Regulárne výrazy: bez ^ a $ vzor kontroluje len to, či sa niekde v texte vyskytuje, nie či sedí celá hodnota.
  5. Polia namiesto reťazcov: útočník môže namiesto textu poslať pole. Bez kontroly typu to vedie k upozorneniam alebo neočakávanému správaniu.
Tip

Pre pevné hodnoty výberu, ako zoradenie, jazyk alebo spôsob dopravy, je zoznam povolených hodnôt pomocou in_array($wert, $erlaubt, true) alebo výrazu match jednoduchší a prísnejší než ktorýkoľvek regulárny výraz.

Ďalšia častá chyba sa týka čísel s významom, napríklad cien, množstiev alebo zliav. To, že hodnota je platné číslo, nehovorí nič o tom, či je v danej súvislosti dovolená. Záporné množstvo, zľava vyššia než hodnota tovaru alebo cena prevzatá z formulára namiesto z databázy sú klasické logické chyby. Ceny, oprávnenia a stavové hodnoty preto vždy patria na server a nikdy do skrytých polí formulára.

JSON, webhooky a importy: validácia mimo formulárov

Mnohé vstupy dnes už nie sú formuláre, ale požiadavky JSON z aplikácií, webhooky od platobných služieb alebo importné súbory od dodávateľov. Aj tu platí: najprv bezpečne načítať, potom skontrolovať. OWASP radí obmedziť veľkosť a hĺbku vnorenia ešte pred načítaním údajov. V PHP časť z toho preberá json_decode() s maximálnou hĺbkou a JSON_THROW_ON_ERROR:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // najviac 64 KB
try {
    $daten = json_decode($roh, true, 16, JSON_THROW_ON_ERROR);
} catch (JsonException) {
    http_response_code(400);
    exit;
}
if (!is_array($daten) || !is_string($daten['bestellnummer'] ?? null)) {
    http_response_code(422);
    exit;
}

Pri webhookoch stojí pred obsahovou kontrolou otázka, či správa skutočne pochádza z uvedenej služby. Ak služba ponúka podpis, skontrolujte ho a porovnajte pomocou hash_equals(). Pri importných súboroch skontrolujte každý riadok ako formulár a pri chybách čisto prerušte, namiesto preberania polovičných záznamov.

Chybové hlásenia by mali uvádzať dotknuté pole, odmietnutú hodnotu by však nemali vracať nefiltrovanú. Inak vznikne na chybovom hlásení samotnom nové miesto výstupu, ktoré sa musí opäť kódovať.

Čo validácia nedokáže

Validácia zmenšuje útočnú plochu, ale podľa OWASP nie je hlavnou obranou proti injection. Priezvisko s apostrofom je platné a napriek tomu sa musí bezpečne dostať do databázy. To sa podarí len pomocou Prepared Statements, ako ukazuje sprievodca Ako zabrániť SQL injection v PHP. A platný text komentára sa stane neškodným až kódovaním primeraným kontextu pri výstupe.

Správne poradie teda znie: pri prijatí validovať, pri spracovaní parametrizovať, pri výstupe kódovať. Pred to patria aj limity veľkosti: požiadavky, ktoré sú oveľa príliš veľké, by webserver a PHP nemali ani spracovať celé. Slúžia na to nastavenia ako post_max_size, ktoré by sa mali po PHP2Shell tak či tak skontrolovať.

Ako konkrétne pomáha PHP SOS?

  • Zachytíme všetky vstupy vašej aplikácie: formuláre, rozhrania, uploady, importy a webhooky.
  • Pre každé pole určíme, čo je dovolené, a plošné čistiace funkcie nahradíme jasnými kontrolami.
  • Preveríme, či sú prístupy do databázy a výstupy zabezpečené nezávisle od validácie.
  • Pravidlá zdokumentujeme tak, aby ich váš tím mohol pri nových funkciách dodržiavať ďalej.

Systematickú kontrolu opisuje služba Bezpečnostný audit a penetračný test.

Časté otázky

Aký je rozdiel medzi validáciou a čistením?

Validácia kontroluje, či hodnota zodpovedá očakávaniam, a ak nie, odmietne ju. Čistenie hodnotu mení, napríklad odstránením znakov. Pre bezpečnostné rozhodnutia je takmer vždy lepšie odmietnuť, pretože mlčky zmenená hodnota môže vyvolať nové chyby.

Dá sa FILTER_SANITIZE_STRING ešte používať?

Filter je od PHP 8.1 označený ako zastaraný. Príručka PHP namiesto toho odporúča htmlspecialchars() pri výstupe. Existujúci kód by ste mali prestaviť, pretože zastarané funkcie môžu v budúcich verziách zaniknúť.

Stačí FILTER_VALIDATE_URL na zabezpečenie odkazov?

Nie. Filter kontroluje len tvar adresy. Podľa príručky nemusí platná URL začínať http, preto musíte schému sami skontrolovať voči zoznamu povolených hodnôt, ako je https. Internacionalizované názvy domén filter odmieta.

Musím validovať aj údaje z vlastnej databázy?

Pri výstupe sa považujú za nedôveryhodné a primerane sa kódujú. Opätovná validácia má zmysel, ak údaje pôvodne prišli zvonka a teraz sa používajú v novej súvislosti, napríklad ako názov súboru alebo časť príkazu.

Pomáha validácia proti PHP2Shell?

Nie. PHP2Shell sa týka spracovania požiadaviek v interpreteri PHP skôr, než vôbec začne bežať kód vašej aplikácie. Proti tomu pomáha len aktualizácia PHP s následným reštartom všetkých procesov PHP.

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