Trenutno stanje: PHP2Shell. Dve kritični ranljivosti PHP (CVSS 9,2) omogočata izvedbo škodljive kode brez prijave. Popravki od 21. 10. 2026.Kaj je zdaj treba storiti →

Preverjanje in filtriranje vnosov v PHP s filter_var

Kako razvijalci v PHP preverjajo vnose s filter_var, filter_input_array in dovoljenimi seznami, kateri filtri so zastareli in zakaj preverjanje ne nadomesti pripravljenih stavkov ter kodiranja izpisa.

Stanje 5 min branjaVaren razvoj

Na kratko: Vnose v PHP preverjate s filter_var() ali filter_input_array() in jasnimi pravili za vsako polje: tip, obseg, dolžina in dovoljene vrednosti. Kar ne ustreza, se zavrne, ne pa tiho predela. Preverjanje je pomembno za čiste podatke in manjšo napadalno površino, a ne nadomesti niti pripravljenih stavkov (prepared statements) proti SQL injection niti kodiranja, ustreznega kontekstu, proti XSS.

Zakaj „filtriraj vse“ ni zasnova

V mnogih starejših projektih PHP je na začetku vsake datoteke zanka, ki vse vrednosti iz $_GET in $_POST pošlje skozi funkcijo za čiščenje. To daje občutek varnosti. V praksi včasih odstrani preveč, na primer opuščaje v priimkih, včasih premalo, ker naj bi ista funkcija hkrati veljala za SQL, HTML in imena datotek.

Smiselno preverjanje deluje drugače: za vsako polje se vpraša, kaj je tam dovoljeno. Naročena količina je celo število med 1 in zgornjo mejo. Polje za razvrščanje je ena od treh stalnih vrednosti. Datum je v določeni obliki in pred drugim datumom ali po njem. Vse drugo se zavrne.

OWASP pri tem razlikuje dve ravni: sintaktično preverjanje, ali ima vrednost pravo obliko, in semantično preverjanje, ali v kontekstu ima smisel. Obe sodita na strežnik; preverjanja v brskalniku služijo samo uporabnosti.

Kateri filtri so vgrajeni v PHP

Razširitev filter je privzeto vključena v PHP. Najpomembnejši filtri za preverjanje po priročniku PHP:

Filter Preverja Pomembne možnosti in opombe
FILTER_VALIDATE_INT celo število min_range, max_range
FILTER_VALIDATE_FLOAT število z decimalko decimal za ločilo
FILTER_VALIDATE_BOOL logična vrednost z FILTER_NULL_ON_FAILURE ločljivo od „false“
FILTER_VALIDATE_EMAIL oblika e-poštnega naslova ne dokazuje, da nabiralnik obstaja
FILTER_VALIDATE_URL oblika URL shemo preverite sami, brez mednarodnih domen
FILTER_VALIDATE_IP naslov IP zastavice za zasebna in rezervirana območja
FILTER_VALIDATE_REGEXP lasten vzorec vzorec zasidrajte z ^ in $

Filter za čiščenje FILTER_SANITIZE_STRING je od PHP 8.1 zastarel. Kdor ga še uporablja, naj preverjanje prestavi na ustrezne filtre in za izpis uporabi htmlspecialchars().

filter_var v PHP: pravilno preverjanje obrazca

S filter_input_array() je mogoče cel obrazec preveriti v enem koraku glede na definicijo. Neznana polja se pri tem ne prevzamejo:

<?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);
    // Izpišite sporočilo o napaki za vsako polje, vnosov ne obdelujte
}

Upoštevajte stroge primerjave z ===: veljavne vrednosti 0 ali praznega niza ne smete zamenjati z neuspehom. Zakaj so ohlapne primerjave tu nevarne, pojasnjuje Type juggling: ohlapne primerjave kot varnostno tveganje. Kako PHP sploh daje na voljo podatke zahtev, opisuje Superglobals: $_GET, $_POST, $_FILES in drugi.

Pasti pri e-pošti, URL in prostem besedilu

Nekateri filtri naredijo manj, kot bi sklepali po imenu:

  1. URL-ji: FILTER_VALIDATE_URL sprejme tudi druge sheme kot http in https. Shemo nato s parse_url() preverite proti stalnemu seznamu. Če strežnik URL pridobiva, veljajo dodatna pravila, glejte Preprečevanje Server-Side Request Forgery v PHP.
  2. E-poštni naslovi: Filter preverja obliko, ne lastništva. Kdor mora biti prepričan, pošlje potrditveno povezavo.
  3. Prosto besedilo: Imen, sporočil in naslovov skoraj ni smiselno omejiti na znake. Preverite dolžino in kodiranje znakov, na primer z mb_check_encoding($wert, 'UTF-8'), pri izpisu pa se zanesite na kodiranje.
  4. Regularni izrazi: Brez ^ in $ vzorec preveri samo, ali se nekje v besedilu pojavlja, ne pa ali ustreza celotna vrednost.
  5. Polja namesto nizov: Napadalec lahko namesto besedila pošlje polje. Brez preverjanja tipa to vodi do opozoril ali nepričakovanega obnašanja.
Nasvet

Za stalne izbirne vrednosti, kot so razvrščanje, jezik ali način dostave, je dovoljeni seznam z in_array($wert, $erlaubt, true) ali izrazom match preprostejši in strožji od vsakega regularnega izraza.

Druga pogosta napaka zadeva števila s pomenom, na primer cene, količine ali popuste. Dejstvo, da je vrednost veljavno število, ne pove ničesar o tem, ali je v kontekstu dovoljena. Negativna količina, popust nad vrednostjo blaga ali cena, prevzeta iz obrazca namesto iz baze podatkov, so klasične logične napake. Cene, pooblastila in vrednosti stanja zato vedno sodijo na strežnik in nikoli v skrita polja obrazca.

JSON, webhooki in uvozi: preverjanje onkraj obrazcev

Mnogi vhodi danes niso več obrazci, ampak zahteve JSON iz aplikacij, webhooki ponudnikov plačil ali uvozne datoteke dobaviteljev. Tudi tam velja: najprej varno prebrati, nato preveriti. OWASP svetuje, da se velikost in globina gnezdenja omejita, še preden se podatki sploh preberejo. V PHP del tega prevzame json_decode() z največjo globino in JSON_THROW_ON_ERROR:

<?php
$roh = file_get_contents('php://input', false, null, 0, 65536); // največ 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 webhookih pred vsebinskim preverjanjem stoji vprašanje, ali sporočilo res prihaja od navedene storitve. Če storitev ponuja podpis, ga preverite in primerjajte s hash_equals(). Pri uvoznih datotekah vsako vrstico preverite kot obrazec in ob napakah čisto prekinite, namesto da bi prevzeli napol zapise.

Sporočila o napakah naj navedejo prizadeto polje, zavrnjene vrednosti pa naj ne vračajo nefiltrirane. Sicer nastane na samem sporočilu o napaki novo mesto izpisa, ki ga je treba spet kodirati.

Česa preverjanje ne zmore

Preverjanje zmanjša napadalno površino, a po OWASP ni glavna obramba pred injection. Priimek z opuščajem je veljaven in vseeno mora varno priti v bazo podatkov. To uspe samo s pripravljenimi stavki, kot kaže vodnik Preprečevanje SQL injection v PHP. In veljavno besedilo komentarja postane neškodljivo šele s kodiranjem, ustreznim kontekstu, pri izpisu.

Pravilni vrstni red je torej: ob prejemu preveriti, pri obdelavi parametrizirati, pri izpisu kodirati. Dodatno sodijo pred to omejitve velikosti: zahtev, ki so veliko prevelike, spletni strežnik in PHP sploh ne bi smela v celoti obdelati. Za to služijo nastavitve, kot je post_max_size, ki bi jih bilo po PHP2Shell tako ali tako treba preveriti.

Kako konkretno pomaga PHP SOS?

  • Zajamemo vse vhode vaše aplikacije: obrazce, vmesnike, nalaganja, uvoze in webhooke.
  • Za vsako polje določimo, kaj je dovoljeno, in splošne funkcije za čiščenje nadomestimo z jasnimi preverjanji.
  • Preverimo, ali so dostopi do baze podatkov in izpisi zavarovani neodvisno od preverjanja.
  • Pravila dokumentiramo tako, da jih vaša ekipa lahko nadaljuje pri novih funkcijah.

Sistematičen pregled opisuje storitev Varnostni pregled in penetracijski test.

Pogosta vprašanja

Kakšna je razlika med preverjanjem in čiščenjem?

Preverjanje ugotovi, ali vrednost ustreza pričakovanjem, in jo sicer zavrne. Čiščenje vrednost spremeni, na primer z odstranitvijo znakov. Za varnostne odločitve je skoraj vedno bolje zavrniti, ker lahko tiho spremenjena vrednost povzroči nove napake.

Ali je FILTER_SANITIZE_STRING še uporaben?

Filter je od PHP 8.1 označen kot zastarel. Priročnik PHP namesto tega priporoča htmlspecialchars() pri izpisu. Obstoječo kodo naj prilagodite, ker lahko zastarele funkcije v prihodnjih različicah odpadejo.

Ali FILTER_VALIDATE_URL zadošča za varne povezave?

Ne. Filter preverja samo obliko naslova. Po priročniku veljavni URL ni nujno, da se začne s http, zato morate shemo sami preveriti proti dovoljenemu seznamu, kot je https. Mednarodnih domenskih imen filter ne sprejme.

Ali moram preverjati tudi podatke iz lastne baze?

Pri izpisu veljajo za nezaupanja vredne in se ustrezno kodirajo. Ponovno preverjanje je smiselno, če so podatki izvirno prišli od zunaj in se zdaj uporabljajo v novem okviru, na primer kot ime datoteke ali del ukaza.

Ali preverjanje pomaga proti PHP2Shell?

Ne. PHP2Shell zadeva obdelavo zahtev v interpreterju PHP, še preden sploh teče koda vaše aplikacije. Proti temu pomaga samo posodobitev PHP s sledečim ponovnim zagonom vseh procesov PHP.

Viri

Takojšnji stik

Vsaka ura šteje. Pišite nam zdaj.

Na kratko opišite sistem, različico PHP in opažanje. Odzovemo se, razjasnimo stanje in delamo na daljavo, dokler incident ni zaključen in dokumentiran.

Takojšnja pomoč