Lühidalt: Local File Inclusion PHP-s tekib, kui include, require või failifunktsioonid kasutavad teed, mida külastaja saab mõjutada. Turvaline lahendus on kindel lubatud nimekiri: parameeter valib ainult tuntud väärtuste seast, tee ise ei tule kunagi päringust. Serveri poolel täiendavad kaitset allow_url_include=Off, open_basedir ja piiravad failiõigused.
Mis on Local File Inclusion PHP-s?
Paljud vanemad PHP rakendused laadivad lehti lihtsa mustri järgi: aadressi parameeter määrab, milline fail lisatakse. Kui see parameeter antakse kontrollimata käsule include, saab ründaja nõuda serveris teisi faile. Healoomulisemal juhul loeb ta välja ligipääsuandmetega seadistusfaile. Halvemal juhul paneb ta PHP käivitama sisu, mille ta on varem mujale paigutanud, näiteks üleslaaditud faili või logifaili.
Juhatuse jaoks on oluline: see turvaauk asub harva sisuhaldussüsteemi tuumas, vaid enamasti oma arendustes, vanades laiendustes või kiiresti ehitatud lisalehtedes. Igapäevaselt see silma ei jää, sest veebisait töötab normaalselt.
Remote File Inclusion puhul laadib PHP koodi võõralt aadressilt. See eeldab, et allow_url_include on aktiveeritud. Praegustes PHP versioonides on see seade vaikimisi väljas, kuid vanades või valesti seadistatud serverites võib seda veel leida.
Tüüpilised haavatavad mustrid koodis
Ohustatud on kohad, kus päringust, küpsistest või andmebaasist pärit väärtus muutub faili tee osaks. Sagedased näited on keelevahetajad, mis laadivad keelefaili parameetri järgi, lehevalik aadressi parameetri kaudu, malli või teema valik ning dokumentide allalaadimisskriptid. Tee lõppu lisatud .php ei kaitse seejuures usaldusväärselt, sest ründajad saavad kõrvale kalduda olemasolevatele PHP failidele.
Esimese ülevaate saate otsinguga lisamiste järgi, mis sisaldavad muutujaid. See annab ka kahjutuid tabamusi, kuid näitab, kuhu täpsemalt vaadata:
grep -rnE --include='*.php' '(include|require)(_once)?\s*\(?\s*\$' /var/www/projekt \
| grep -v '/vendor/'
Kontrollige iga tabamust selle suhtes, kust muutuja pärineb ja kas külastaja saab seda mõjutada.
Turvaline muster: lubatud nimekiri päringust pärit tee asemel
Usaldusväärseim kaitse on, et külastaja valib ainult võtme ja rakendus otsustab ise, milline fail sellele kuulub. Teed ei panda kunagi sisendist kokku.
<?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];
See muster on lühike, lihtne kontrollida ega jäta mänguruumi. Kaasaegsetes raamistikes võtab selle ülesande üle ruuter; ka seal ei tohiks kontrollereid ja malle määrata vabade parameetrite järgi.
Kui failinimed peavad olema dünaamilised: realpath ja baaskataloog
Mõnikord ei ole kindel nimekiri praktiline, näiteks dokumendikaustast allalaadimiste puhul. Siis kontrollite lahendatud teed kindla baaskataloogi vastu ja lubate ainult lihtsad failinimed.
<?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;
}
// Väljastada, mitte lisada: readfile() ei käivita koodi.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);
Kaks punkti on otsustavad. Regulaaravaldis ei luba kataloogieraldajaid ega erimärke. Ja failid, mis tuleb ainult väljastada, loetakse käsuga readfile(), mitte include, et sisalduv kood ei käivituks kunagi. str_starts_with() on saadaval alates PHP 8.0-st.
Serveripoolne kaitse: php.ini, open_basedir ja õigused
Turvaline kood on esimene kaitseliin. Serveri seadistus tagab, et märkamata jäänud viga teeb vähem kahju.
; php.ini või FPM-i pool (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen = Off ; ainult siis, kui rakendus ei laadi väliseid URL-e
open_basedir = /var/www/kunde-a/:/tmp/kunde-a/
display_errors = Off
log_errors = On
allow_url_fopen vajavad mõned rakendused uuenduste või liideste jaoks. Testige selle väljalülitamist esmalt testkeskkonnas. open_basedir piirab PHP veebisaidi enda kataloogidega, mis on eriti oluline mitme kliendiga serverites. Üksikasjad on juhendites open_basedir ja isolatsioon veebisaidi kaupa ja php.ini turvaline seadistamine.
Lisaks ei tohiks üleslaadimis- ja vahemälukaustad olla käivitatavad ning logifailid ei tohiks asuda veebijuures. Siis puuduvad ründajal kohad, kuhu ta saaks lisamiseks oma sisu paigutada.
Kuidas ärakasutamiskatseid logidest ära tunda
Faili lisamise ärakasutamise katsed jätavad tavaliselt jälgi juurdepääsulogisse. Silma torkavad parameetrid, mis sisaldavad kataloogivahetusi, absoluutseid süsteemiteid, voo ümbriseid (stream wrapper) või täielikke võõraid aadresse, eriti parameetrite nagu page, file, template või lang puhul. Üksik tabamus on enamasti automatiseeritud skaneerimine. Oluline on, kas selline päring vastati olekukoodiga 200 ja ebatavalise vastuse suurusega.
Kuidas seejuures süstemaatiliselt toimida, kirjeldab juhend Veebiserveri logide analüüs pärast rünnakut. Kui leiate vihjeid õnnestunud juurdepääsule, lähtuge sellest, et seadistusfaile loeti, ja uuendage neis sisalduvad ligipääsuandmed.
Siia kuuluvad eelkõige andmebaasiparoolid, makse- ja saatmisteenuste võtmed, SMTP ligipääsud ning sisuhaldussüsteemi salavõtmed. Kontrollige lisaks, kas pärast esimest kahtlast juurdepääsu on tekkinud uusi faile. Kes sai faile lugeda, on võib-olla püüdnud ka oma faile paigutada. Sel juhul ei ole enam tegemist ainult koodi turvaaugu, vaid turvaintsidendiga, mida tuleks struktureeritult käsitleda.
Parandused püsivalt kindlustada
Pärast parandust tasub kaitsefunktsiooni automaattestidega kindlustada. Lihtne test annab lehevalikule tundmatuid väärtusi, kataloogivahetusi ja tühje sisendeid ning ootab kõigil juhtudel vaikelehte või viga 404. Sellised testid takistavad, et hilisem muudatus turvaauku märkamatult uuesti avab.
Juhatuse ja projektijuhtide jaoks on abiks küsimus agentuurile: kas rakenduses on kohti, kus faile laaditakse parameetrite järgi, ja kuidas need on kaitstud? Konkreetne vastus leiukohtade ja testidega on hea märk.
Kuidas PHP SOS konkreetselt aitab?
- Otsime teie koodist sihipäraselt
include,requireja failifunktsioone päringust pärit sisendiga ning hindame iga leidu. - Seame
allow_url_include,open_basedirja sobivad õigused veebisaidi kaupa ning kontrollime, et rakendus pärast seda edasi töötab. - Analüüsime logisid ärakasutamiskatsete suhtes ja selgitame, kas ligipääsuandmeid tuleb uuendada.
- Sõltumatuks kontrolliks pakume PHP rakendustele turvaauditit koos penetratsioonitestiga.
Korduma kippuvad küsimused
Mis vahe on LFI ja RFI vahel?
Local File Inclusion puhul laadib rakendus faili, mis juba serveris on, kuid mida ei tohiks laadida. Remote File Inclusion puhul laaditakse kood võõralt aadressilt. RFI eeldab ebaturvalist PHP seadet, LFI mitte.
Kas piisab parameetrist ../ eemaldamisest?
Ei. Selliseid filtreid saab sageli kodeeringu või variantidega kõrvale kalduda ja need jätavad märkamata absoluutsed teed. Turvaline on ainult lubatud väärtuste kindel vastavus failidele või lahendatud tee kontroll baaskataloogi vastu.
Kas open_basedir kaitseb faili lisamise eest täielikult?
Ei, see piirab ainult katalooge, millele PHP-l on juurdepääs. Nende piiride sees jääb turvaauk ärakasutatavaks. open_basedir on täiendav kaitsekiht ega asenda turvalist koodi.
Kas sisuhaldussüsteemid nagu WordPress on LFI-st mõjutatud?
Levinud sisuhaldussüsteemide tuuma peetakse selles punktis hästi kontrollituks. Turvauke ilmneb pigem laiendustes, teemades ja oma arendustes. Laienduste uuendused ja pilk nende turvateadetesse on seetõttu olulised.