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 →

Preprečevanje Local File Inclusion v PHP: LFI in RFI

Če include ali require prevzameta poti iz zahteve, lahko napadalci naložijo tuje datoteke. Kako varno zgradite izbiro strani in predloge ter strežnik dodatno zaščitite.

Stanje 5 min branjaPriročniki

Na kratko: Local File Inclusion v PHP nastane, ko include, require ali funkcije za datoteke uporabijo pot, na katero lahko vpliva obiskovalec. Varna rešitev je trden seznam dovoljenih vrednosti: parameter izbira samo med znanimi vrednostmi, sama pot nikoli ne izvira iz zahteve. Na strani strežnika zaščito dopolnjujejo allow_url_include=Off, open_basedir in restriktivne pravice datotek.

Kaj je Local File Inclusion v PHP?

Številne starejše aplikacije PHP strani nalagajo po preprostem vzorcu: parameter v naslovu določa, katera datoteka se vključi. Če se ta parameter nepreverjen preda include, lahko napadalec zahteva druge datoteke na strežniku. V milejšem primeru prebere konfiguracijske datoteke z dostopnimi podatki. V hujšem primeru PHP prisili, da izvede vsebine, ki jih je prej odložil drugje, na primer v nalaganju ali dnevniški datoteki.

Za vodstvo je pomembno: ta ranljivost redko tiči v jedru CMS-ja, običajno pa v lastnih razvojih, starih razširitvah ali na hitro zgrajenih dodatnih straneh. V vsakdanu ne pade v oči, ker spletna stran deluje normalno.

Pri Remote File Inclusion PHP naloži kodo s tujega naslova. To predpostavlja, da je allow_url_include vklopljen. V aktualnih različicah PHP je ta nastavitev privzeto izklopljena, na starih ali napačno konfiguriranih strežnikih pa se še najde.

Tipični ranljivi vzorci v kodi

Ogrožena so mesta, kjer vrednost iz zahteve, piškotkov ali podatkovne zbirke postane del poti do datoteke. Pogosti primeri so preklopniki jezika, ki jezikovno datoteko naložijo po parametru, izbira strani prek parametra v naslovu, izbira predlog ali tem in skripte za prenos dokumentov. Pripeta končnica .php na koncu poti pri tem ne ščiti zanesljivo, ker lahko napadalci preidejo na obstoječe datoteke PHP.

Prvi pregled dobite z iskanjem vključitev, ki vsebujejo spremenljivke. Vrne tudi neškodljive zadetke, vendar pokaže, kje je treba pogledati natančneje:

grep -rnE --include='*.php' '(include|require)(_once)?\s*\(?\s*\$' /var/www/projekt \
  | grep -v '/vendor/'

Pri vsakem zadetku preverite, od kod izvira spremenljivka in ali lahko obiskovalec nanjo vpliva.

Varen vzorec: seznam dovoljenih namesto poti iz zahteve

Najzanesljivejša zaščita je, da obiskovalec izbere samo ključ, aplikacija pa sama odloči, katera datoteka mu pripada. Pot se nikoli ne sestavi iz vnosov.

<?php
declare(strict_types=1);

$seiten = [
    'start'      => __DIR__ . '/../vorlagen/start.php',
    'leistungen' => __DIR__ . '/../vorlagen/leistungen.php',
    'kontakt'    => __DIR__ . '/../vorlagen/kontakt.php',
];

$wahl = is_string($_GET['seite'] ?? null) ? $_GET['seite'] : 'start';

if (!array_key_exists($wahl, $seiten)) {
    http_response_code(404);
    $wahl = 'start';
}

require $seiten[$wahl];

Ta vzorec je kratek, ga je lahko preveriti in ne pušča manevrskega prostora. V sodobnih ogrodjih to nalogo prevzame usmerjevalnik; tudi tam krmilnikov in predlog nikoli ne določajte iz prostih parametrov.

Če morajo biti imena datotek dinamična: realpath in osnovna mapa

Včasih trden seznam ni izvedljiv, na primer pri prenosih iz mape z dokumenti. Tedaj razrešeno pot preverite glede na trdno osnovno mapo in dovolite samo preprosta imena datotek.

<?php
declare(strict_types=1);

const BASIS = '/var/www/daten/dokumente';

function sichererPfad(string $name): string
{
    if (!preg_match('/^[a-z0-9_-]{1,64}\.pdf$/', $name)) {
        throw new InvalidArgumentException('Ungültiger Dateiname.');
    }

    $basis = realpath(BASIS);
    $pfad  = realpath($basis . DIRECTORY_SEPARATOR . $name);

    if ($basis === false || $pfad === false
        || !str_starts_with($pfad, $basis . DIRECTORY_SEPARATOR)) {
        throw new RuntimeException('Datei nicht gefunden.');
    }

    return $pfad;
}

// Dostavite namesto vključite: readfile() ne izvaja kode.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

Dve točki sta odločilni. Regularni izraz ne dovoljuje ločil map in posebnih znakov. In datoteke, ki jih je treba samo dostaviti, se preberejo z readfile(), ne z include, da se vsebovana koda nikoli ne izvede. str_starts_with() je na voljo od PHP 8.0.

Zaščita na strani strežnika: php.ini, open_basedir in pravice

Varna koda je prva obrambna linija. Konfiguracija strežnika poskrbi, da spregledana napaka povzroči manj škode.

; php.ini ali pool FPM (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; samo če aplikacija ne nalaga zunanjih URL-jev
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

allow_url_fopen nekatere aplikacije potrebujejo za posodobitve ali vmesnike. Izklop najprej preizkusite v testnem okolju. open_basedir PHP omeji na lastne mape spletne strani, kar je posebej pomembno na strežnikih z več strankami. Podrobnosti so v vodnikih open_basedir in izolacija po spletnih straneh in Varna konfiguracija php.ini.

Dodatno naj mape za nalaganje in predpomnilnik ne bodo izvršljive, dnevniške datoteke pa naj ne ležijo v korenu spleta. Tako napadalcu manjkajo mesta, kjer bi lahko odložil lastno vsebino za vključitev.

Po čem v dnevnikih prepoznate poskuse izkoriščanja

Poskusi izkoriščanja file inclusion običajno pustijo sledi v dnevniku dostopov. Opazni so parametri, ki vsebujejo menjave map, absolutne sistemske poti, ovojnice tokov ali popolne tuje naslove, posebej pri parametrih, kot so page, file, template ali lang. Posamezen zadetek je običajno samodejno skeniranje. Pomembno je, ali je bila taka zahteva odgovorjena s statusno kodo 200 in nenavadno velikostjo odgovora.

Kako pri tem ukrepate sistematično, opisuje vodnik Analiza dnevnikov spletnega strežnika po napadu. Če najdete namige na uspešne dostope, izhajajte iz tega, da so bile konfiguracijske datoteke prebrane, in obnovite v njih vsebovane dostopne podatke.

Sem sodijo predvsem gesla podatkovnih zbirk, ključi za plačilne in dostavne storitve, dostopi SMTP in skrivni ključi CMS-ja. Preverite tudi, ali so po prvem sumljivem dostopu nastale nove datoteke. Kdor je lahko bral datoteke, je morda poskusil odložiti tudi lastne. V tem primeru ne gre več samo za ranljivost v kodi, ampak za varnostni incident, ki ga je treba obravnavati strukturirano.

Popravke trajno zavarujte

Po popravku se splača zaščitno funkcijo zavarovati z avtomatiziranimi testi. Preprost test izbiri strani preda neznane vrednosti, menjave map in prazne vnose ter v vseh primerih pričakuje privzeto stran ali napako 404. Takšni testi preprečijo, da bi poznejša sprememba neopazno znova odprla ranljivost.

Za vodstvo in vodje projektov je koristno vprašanje agenciji: ali so v aplikaciji mesta, kjer se datoteke nalagajo na podlagi parametrov, in kako so zaščitena? Konkreten odgovor z navedbo mest in testov je dober znak.

Kako PHP SOS pomaga konkretno?

  • V vaši kodi ciljno iščemo include, require in funkcije za datoteke z vnosi iz zahteve ter vsako najdbo ocenimo.
  • Nastavimo allow_url_include, open_basedir in ustrezne pravice za vsako spletno stran ter preverimo, da aplikacija po tem še deluje.
  • Dnevnike ovrednotimo glede poskusov izkoriščanja in razjasnimo, ali je treba dostopne podatke obnoviti.
  • Za neodvisno preverjanje ponujamo varnostni pregled s penetracijskim testom za aplikacije PHP.

Pogosta vprašanja

Kakšna je razlika med LFI in RFI?

Pri Local File Inclusion aplikacija naloži datoteko, ki že leži na strežniku, a je ne bi smela naložiti. Pri Remote File Inclusion se koda naloži s tujega naslova. RFI predpostavlja nevarno nastavitev PHP, LFI ne.

Ali zadošča, da iz parametra odstranim ../?

Ne. Takšne filtre je pogosto mogoče zaobiti s kodiranjem ali različicami in spregledajo absolutne poti. Varna je samo trdna dodelitev dovoljenih vrednosti datotekam ali preverjanje razrešene poti glede na osnovno mapo.

Ali open_basedir popolnoma ščiti pred file inclusion?

Ne, omejuje samo mape, do katerih sme PHP dostopati. Znotraj teh meja ostaja ranljivost izkoristljiva. open_basedir je dodatna zaščitna plast in varne kode ne nadomesti.

Ali so CMS-ji, kot je WordPress, prizadeti zaradi LFI?

Jedro običajnih CMS-jev velja v tem pogledu za dobro preverjeno. Ranljivosti se prej pojavijo v razširitvah, temah in lastnih razvojih. Posodobitve razširitev in pogled v njihova varnostna obvestila so zato pomembni.

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č