Aktuālā situācija: PHP2Shell. Divas kritiskas PHP ievainojamības (CVSS 9.2) ļauj izpildīt ļaunprātīgu kodu bez pieteikšanās. Ielāpi kopš 21.10.2026.Kas jādara tagad →

Local File Inclusion novēršana PHP: LFI un RFI

Ja include vai require pārņem ceļus no pieprasījuma, uzbrucēji var ielādēt svešus failus. Kā droši veidot lapu izvēli un veidnes un papildus nodrošināt serveri.

Aktuāls uz 5 min lasīšanas laiksRokasgrāmatas

Īsi: Local File Inclusion PHP rodas, kad include, require vai failu funkcijas izmanto ceļu, ko apmeklētājs var ietekmēt. Drošais risinājums ir fiksēts atļauju saraksts: parametrs izvēlas tikai no zināmām vērtībām, pats ceļš nekad nenāk no pieprasījuma. Servera pusē aizsardzību papildina allow_url_include=Off, open_basedir un ierobežojošas failu tiesības.

Kas ir Local File Inclusion PHP?

Daudzas vecākas PHP lietojumprogrammas lapas ielādē pēc vienkārša parauga: parametrs adresē nosaka, kurš fails tiek iekļauts. Ja šis parametrs bez pārbaudes tiek nodots include, uzbrucējs var pieprasīt citus failus serverī. Nekaitīgākā gadījumā viņš nolasa konfigurācijas failus ar piekļuves datiem. Sliktākā gadījumā viņš panāk, ka PHP izpilda saturu, ko viņš iepriekš novietojis citur, piemēram, augšupielādē vai žurnāla failā.

Vadībai svarīgi: šī ievainojamība reti atrodas CMS kodolā, bet gan pašu izstrādājumos, vecos paplašinājumos vai steigā uzbūvētās papildu lapās. Ikdienā tā nekrīt acīs, jo vietne darbojas normāli.

Remote File Inclusion gadījumā PHP ielādē kodu no svešas adreses. Tam nepieciešams, lai allow_url_include būtu aktivizēts. Aktuālajās PHP versijās šis iestatījums pēc noklusējuma ir izslēgts, taču vecos vai nepareizi konfigurētos serveros to vēl var sastapt.

Tipiski ievainojami paraugi kodā

Apdraudētas ir vietas, kur vērtība no pieprasījuma, sīkdatnēm vai datubāzes kļūst par faila ceļa daļu. Biežākie piemēri ir valodas pārslēdzēji, kas valodas failu ielādē pēc parametra, lapu izvēle ar parametru adresē, veidņu vai motīvu izvēle un dokumentu lejupielādes skripti. Pievienots .php ceļa beigās uzticami neaizsargā, jo uzbrucēji var pāriet uz esošiem PHP failiem.

Pirmo pārskatu iegūstat ar tādu iekļaušanu meklēšanu, kas satur mainīgos. Tā dod arī nekaitīgus atradumus, bet parāda, kur jāskatās precīzāk:

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

Katram atradumam pārbaudiet, no kurienes mainīgais nāk un vai apmeklētājs to var ietekmēt.

Drošais paraugs: atļauju saraksts nevis ceļš no pieprasījuma

Visuzticamākā aizsardzība ir tā, ka apmeklētājs izvēlas tikai atslēgu, bet lietojumprogramma pati nosaka, kurš fails tai pieder. Ceļš nekad netiek veidots no ievades.

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

Šis paraugs ir īss, viegli pārbaudāms un neatstāj rīcības brīvību. Modernos ietvaros šo uzdevumu pilda maršrutētājs; arī tur kontrolieri un veidnes nekad nedrīkst tikt noteiktas no brīviem parametriem.

Ja failu nosaukumiem jābūt dinamiskiem: realpath un bāzes direktorijs

Dažkārt fiksēts saraksts nav praktisks, piemēram, lejupielādēm no dokumentu mapes. Tad atrisināto ceļu pārbaudiet pret fiksētu bāzes direktoriju un atļaujiet tikai vienkāršus faila nosaukumus.

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

// Piegādāt, nevis iekļaut: readfile() koda neizpilda.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

Izšķiroši ir divi punkti. Regulārā izteiksme neatļauj direktoriju atdalītājus un speciālās rakstzīmes. Un faili, kas jāpiegādā tikai, tiek nolasīti ar readfile(), nevis ar include, lai tajos esošais kods nekad netiktu izpildīts. str_starts_with() ir pieejama no PHP 8.0.

Servera puses aizsardzība: php.ini, open_basedir un tiesības

Drošs kods ir pirmā aizsardzības līnija. Servera konfigurācija nodrošina, ka nepamanīta kļūda nodara mazāk kaitējuma.

; php.ini vai FPM pūls (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; tikai ja lietojumprogramma neielādē ārējus URL
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

allow_url_fopen dažām lietojumprogrammām vajadzīgs atjauninājumiem vai saskarnēm. Izslēgšanu vispirms pārbaudiet testa vidē. open_basedir ierobežo PHP līdz vietnes pašas direktorijiem, kas sevišķi svarīgi serveros ar vairākiem klientiem. Sīkāk ceļvežos open_basedir un izolācija katrai vietnei un php.ini drošā konfigurēšana.

Papildus augšupielāžu un kešatmiņas direktorijiem jābūt neizpildāmiem, bet žurnālu failiem nav jāatrodas webroot. Tā uzbrucējam trūkst vietu, kur novietot savu saturu iekļaušanai.

Kā ekspluatācijas mēģinājumus atpazīt žurnālos

Mēģinājumi izmantot File Inclusion parasti atstāj pēdas piekļuves žurnālā. Uzkrītoši ir parametri, kas satur direktoriju maiņu, absolūtus sistēmas ceļus, stream wrapper vai pilnas svešas adreses, īpaši parametros, piemēram, page, file, template vai lang. Atsevišķs atradums parasti ir automatizēta skenēšana. Svarīgi ir, vai uz šādu pieprasījumu atbildēts ar statusa kodu 200 un neparastu atbildes lielumu.

Kā šajā gadījumā rīkoties sistemātiski, apraksta Tīmekļa servera žurnālu izvērtēšana pēc uzbrukuma. Ja atrodat norādes uz sekmīgām piekļuvēm, pieņemiet, ka konfigurācijas faili ir nolasīti, un atjaunojiet tajos esošos piekļuves datus.

Tur galvenokārt pieder datubāzes paroles, atslēgas maksājumu un piegādes pakalpojumiem, SMTP piekļuves un CMS slepenās atslēgas. Pārbaudiet arī, vai kopš pirmās aizdomīgās piekļuves nav radušies jauni faili. Kas varēja lasīt failus, iespējams, mēģināja arī novietot savus. Šādā gadījumā runa vairs nav tikai par ievainojamību kodā, bet par drošības incidentu, kas apstrādājams strukturēti.

Labojumus nodrošināt ilgtermiņā

Pēc labojuma ir vērts aizsardzības funkciju nodrošināt ar automatizētiem testiem. Vienkāršs tests lapu izvēlei nodod nezināmas vērtības, direktoriju maiņas un tukšu ievadi un visos gadījumos gaida noklusējuma lapu vai kļūdu 404. Šādi testi neļauj vēlākai izmaiņai nemanot atkal atvērt ievainojamību.

Vadībai un projektu atbildīgajiem noderīgs ir jautājums aģentūrai: vai lietojumprogrammā ir vietas, kur faili tiek ielādēti pēc parametriem, un kā tās ir aizsargātas? Konkrēta atbilde ar atrašanās vietām un testiem ir laba zīme.

Kā PHP SOS palīdz konkrēti?

  • Mērķtiecīgi meklējam jūsu kodā include, require un failu funkcijas ar ievadi no pieprasījuma un vērtējam katru atradumu.
  • Iestatām allow_url_include, open_basedir un piemērotas tiesības katrai vietnei un pārbaudām, ka lietojumprogramma pēc tam turpina darboties.
  • Izvērtējam žurnālus uz ekspluatācijas mēģinājumiem un noskaidrojam, vai jāatjauno piekļuves dati.
  • Neatkarīgai pārbaudei piedāvājam PHP lietojumprogrammu drošības auditu ar penetrācijas testu.

Biežāk uzdotie jautājumi

Kāda ir atšķirība starp LFI un RFI?

Local File Inclusion gadījumā lietojumprogramma ielādē failu, kas jau atrodas serverī, bet nebūtu jāielādē. Remote File Inclusion gadījumā kods tiek ielādēts no svešas adreses. RFI prasa nedrošu PHP iestatījumu, LFI ne.

Vai pietiek ar ../ noņemšanu no parametra?

Nē. Šādus filtrus bieži var apiet ar kodējumu vai variantiem, un tie neņem vērā absolūtos ceļus. Droša ir tikai fiksēta atļauto vērtību piesaiste failiem vai atrisinātā ceļa pārbaude pret bāzes direktoriju.

Vai open_basedir pilnībā pasargā no File Inclusion?

Nē, tas ierobežo tikai direktorijus, kuriem PHP drīkst piekļūt. Šajās robežās ievainojamība joprojām ir izmantojama. open_basedir ir papildu aizsargslānis un neaizstāj drošu kodu.

Vai LFI skar CMS, piemēram, WordPress?

Izplatīto CMS kodols šajā ziņā tiek uzskatīts par labi pārbaudītu. Ievainojamības drīzāk parādās paplašinājumos, motīvos un pašu izstrādājumos. Paplašinājumu atjauninājumi un to drošības ziņojumu pārskatīšana tāpēc ir svarīgi.

Avoti

Tūlītējs kontakts

Katra stunda ir svarīga. Rakstiet mums tūlīt.

Īsi aprakstiet sistēmu, PHP versiju un novēroto. Mēs sazināsimies, noskaidrosim situāciju un strādāsim attālināti, līdz incidents ir slēgts un dokumentēts.

Tūlītēja palīdzība