# Local File Inclusion novēršana PHP: LFI un RFI

> Local File Inclusion novēršana PHP: atļauju saraksti nevis ceļi no pieprasījuma, realpath pārbaude, allow_url_include izslēgts, open_basedir.

Avots: https://phpsos.de/lv/ratgeber/lfi-rfi/  
Aktuāls uz: 25.10.2026  
Pakalpojuma sniedzējs: PHP SOS, PHP ārkārtas palīdzība un serveru drošība. Tūlītēja palīdzība pa WhatsApp: https://wa.me/491736494914?text=Sveiki%2C%20PHP%20SOS%2C%20mums%20nepiecie%C5%A1ama%20pal%C4%ABdz%C4%ABba%20ar%20m%C5%ABsu%20PHP%20serveri.%20Uz%C5%86%C4%93mums%3A%20%E2%80%A6%20Vietne%3A%20%E2%80%A6

**Ī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:

```bash
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
<?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
<?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.

```ini
; 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](https://phpsos.de/lv/ratgeber/open-basedir/) un [php.ini drošā konfigurēšana](https://phpsos.de/lv/ratgeber/php-ini-sicher-konfigurieren/).

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](https://phpsos.de/lv/ratgeber/logfiles-auswerten/). 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](https://phpsos.de/lv/leistungen/sicherheitsaudit-penetrationstest/).


## 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

- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [BSI IT-Grundschutz](https://www.bsi.bund.de/DE/Themen/Unternehmen-und-Organisationen/Standards-und-Zertifizierung/IT-Grundschutz/it-grundschutz_node.html)
