Trenutno stanje: PHP2Shell. Dvije kritične PHP ranjivosti (CVSS 9.2) omogućuju zlonamjerni kod bez prijave. Zakrpe od 21. 10. 2026.Što sada učiniti →

Sprječavanje Local File Inclusiona u PHP-u: LFI i RFI

Ako include ili require preuzimaju putanje iz zahtjeva, napadači mogu učitavati tuđe datoteke. Kako sigurno izgraditi odabir stranica i predloške te dodatno osigurati poslužitelj.

Stanje 5 min čitanjaSavjetnik

Ukratko: Local File Inclusion u PHP-u nastaje kad include, require ili funkcije za datoteke koriste putanju na koju posjetitelj može utjecati. Sigurno rješenje je čvrst popis dopuštenog: parametar bira samo između poznatih vrijednosti, a sama putanja nikad ne dolazi iz zahtjeva. Na strani poslužitelja zaštitu dopunjuju allow_url_include=Off, open_basedir i restriktivna prava datoteka.

Što je Local File Inclusion u PHP-u

Mnoge starije PHP aplikacije učitavaju stranice po jednostavnom obrascu: parametar u adresi određuje koja se datoteka uključuje. Ako se taj parametar neprovjereno preda include, napadač može zatražiti druge datoteke na poslužitelju. U bezazlenijem slučaju čita konfiguracijske datoteke s pristupnim podacima. U gorem slučaju natjera PHP da izvrši sadržaje koje je prethodno postavio na drugom mjestu, primjerice u uploadu ili log datoteci.

Za upravu je važno: ta ranjivost rijetko je u jezgri CMS-a, nego najčešće u vlastitim razvojima, starim ekstenzijama ili naprečac izgrađenim dodatnim stranicama. U svakodnevici se ne primjećuje jer web-stranica radi normalno.

Kod Remote File Inclusiona PHP učitava kod s tuđe adrese. To pretpostavlja da je allow_url_include aktiviran. U aktualnim verzijama PHP-a ta je postavka po zadanim postavkama isključena, ali se na starim ili pogrešno konfiguriranim poslužiteljima još nalazi.

Tipični ranjivi obrasci u kodu

Ugrožena su mjesta na kojima vrijednost iz zahtjeva, iz kolačića ili iz baze podataka postaje dio putanje datoteke. Česti su primjeri birači jezika koji učitavaju jezičnu datoteku prema parametru, odabir stranica putem parametra u adresi, odabir predložaka ili tema i skripte za preuzimanje dokumenata. Dodani .php na kraju putanje pritom ne štiti pouzdano jer napadači mogu prijeći na postojeće PHP datoteke.

Prvi pregled dobit ćete pretragom ugradnji koje sadrže varijable. Ona daje i bezazlene pogotke, ali pokazuje gdje treba pogledati pobliže:

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

Za svaki pogodak provjerite odakle varijabla potječe i može li na nju utjecati posjetitelj.

Siguran obrazac: popis dopuštenog umjesto putanje iz zahtjeva

Najpouzdanija zaštita je da posjetitelj bira samo ključ, a aplikacija sama odlučuje koja datoteka mu pripada. Putanja se nikad ne sastavlja iz unosa.

<?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];

Ovaj je obrazac kratak, lako ga je provjeriti i ne ostavlja prostora. U modernim frameworkima tu zadaću preuzima router; i tamo kontrolere i predloške nikad ne treba određivati iz slobodnih parametara.

Kad nazivi datoteka moraju biti dinamički: realpath i osnovni direktorij

Ponekad čvrsti popis nije praktičan, primjerice kod preuzimanja iz mape s dokumentima. Tada razriješenu putanju provjerite prema čvrstom osnovnom direktoriju i dopuštajte samo jednostavna imena datoteka.

<?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;
}

// Isporučiti umjesto uključiti: readfile() ne izvršava kod.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

Dvije su točke odlučujuće. Regularni izraz ne dopušta separatore direktorija ni posebne znakove. A datoteke koje se samo trebaju isporučiti čitaju se s readfile(), a ne s include, kako sadržani kod nikad ne bi bio izvršen. str_starts_with() dostupan je od PHP-a 8.0.

Zaštita na strani poslužitelja: php.ini, open_basedir i prava

Siguran kod prva je linija obrane. Konfiguracija poslužitelja osigurava da previđena pogreška napravi manje štete.

; php.ini ili FPM pool (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; samo ako aplikacija ne učitava vanjske URL-ove
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

allow_url_fopen neke aplikacije trebaju za ažuriranja ili sučelja. Isključivanje najprije testirajte na testnom okruženju. open_basedir ograničava PHP na vlastite direktorije web-stranice, što je osobito važno na poslužiteljima s više klijenata. Pojedinosti su u vodičima open_basedir i izolacija po web-stranici i Sigurna konfiguracija php.ini.

Dopunski mape za upload i cache ne bi smjele biti izvršive, a log datoteke ne bi smjele ležati u webrootu. Tako napadaču nedostaju mjesta na koja bi mogao postaviti vlastiti sadržaj za uključivanje.

Po čemu u logovima prepoznati pokušaje iskorištavanja

Pokušaji iskorištavanja File Inclusiona uglavnom ostavljaju tragove u access logu. Upadljivi su parametri koji sadrže promjene direktorija, apsolutne sistemske putanje, stream wrappere ili potpune tuđe adrese, osobito kod parametara poput page, file, template ili lang. Pojedinačni pogodak najčešće je automatizirano skeniranje. Važno je je li takav zahtjev odgovoren statusnim kodom 200 i neuobičajenom veličinom odgovora.

Kako pritom sustavno postupati, opisuje vodič Analiza logova web-poslužitelja nakon napada. Ako pronađete naznake uspješnih pristupa, pretpostavite da su konfiguracijske datoteke pročitane i obnovite pristupne podatke koje sadrže.

Tu spadaju ponajprije lozinke baze podataka, ključevi za usluge plaćanja i dostave, SMTP pristupi i tajni ključevi CMS-a. Provjerite i jesu li od prvog sumnjivog pristupa nastale nove datoteke. Tko je mogao čitati datoteke, možda je pokušao postaviti i vlastite. U tom slučaju više nije riječ samo o ranjivosti u kodu, nego o sigurnosnom incidentu koji treba strukturirano obraditi.

Trajno osiguravanje ispravaka

Nakon ispravka isplati se zaštitnu funkciju osigurati automatiziranim testovima. Jednostavan test odabiru stranica predaje nepoznate vrijednosti, promjene direktorija i prazne unose te u svim slučajevima očekuje standardnu stranicu ili pogrešku 404. Takvi testovi sprječavaju da kasnija promjena neprimijećeno ponovno otvori ranjivost.

Za upravu i voditelje projekata korisno je pitanje agenciji: Postoje li u aplikaciji mjesta na kojima se datoteke učitavaju prema parametrima i kako su osigurana? Konkretan odgovor s mjestima pronalaska i testovima dobar je znak.

Kako PHP SOS konkretno pomaže?

  • U Vašem kodu ciljano tražimo include, require i funkcije za datoteke s unosima iz zahtjeva te ocjenjujemo svaki nalaz.
  • Postavljamo allow_url_include, open_basedir i odgovarajuća prava po web-stranici te provjeravamo da aplikacija nakon toga i dalje radi.
  • Analiziramo logove na pokušaje iskorištavanja i razjašnjavamo treba li obnoviti pristupne podatke.
  • Za neovisnu provjeru nudimo sigurnosni audit s penetracijskim testom za PHP aplikacije.

Česta pitanja

Koja je razlika između LFI i RFI?

Kod Local File Inclusiona aplikacija učitava datoteku koja već leži na poslužitelju, ali se ne bi smjela učitati. Kod Remote File Inclusiona kod se naknadno učitava s tuđe adrese. RFI pretpostavlja nesigurnu PHP postavku, LFI ne.

Je li dovoljno ukloniti ../ iz parametra?

Ne. Takvi se filtri često zaobilaze kodiranjem ili varijantama i previđaju apsolutne putanje. Siguran je samo čvrst raspored dopuštenih vrijednosti na datoteke ili provjera razriješene putanje prema osnovnom direktoriju.

Štiti li open_basedir potpuno od File Inclusiona?

Ne, samo ograničava direktorije kojima PHP smije pristupati. Unutar tih granica ranjivost ostaje iskoristiva. open_basedir je dodatni zaštitni sloj i ne zamjenjuje siguran kod.

Pogađa li LFI CMS-ove poput WordPressa?

Jezgra uobičajenih CMS-ova u tom je pogledu dobro provjerena. Ranjivosti se češće pojavljuju u ekstenzijama, temama i vlastitim razvojima. Ažuriranja ekstenzija i pogled u njihove sigurnosne objave stoga su važni.

Izvori

Hitni kontakt

Svaki sat se računa. Pišite nam odmah.

Ukratko opišite sustav, verziju PHP-a i opažanje. Javit ćemo Vam se, razjasniti situaciju i raditi na daljinu dok incident nije zaključen i dokumentiran.

Hitna pomoć