Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Forhindr Local File Inclusion i PHP: LFI og RFI

Når include eller require overtager stier fra forespørgslen, kan angribere indlæse fremmede filer. Sådan bygger I sidevalg og skabeloner sikkert og sikrer desuden serveren.

Status 5 min. læsetidVejledninger

Kort sagt: Local File Inclusion i PHP opstår, når include, require eller filfunktioner bruger en sti, som den besøgende kan påvirke. Den sikre løsning er en fast tilladelsesliste: Parameteren vælger kun blandt kendte værdier, selve stien kommer aldrig fra forespørgslen. På serversiden supplerer allow_url_include=Off, open_basedir og restriktive filrettigheder beskyttelsen.

Hvad er Local File Inclusion i PHP?

Mange ældre PHP-applikationer indlæser sider efter et enkelt mønster: En parameter i adressen bestemmer, hvilken fil der indbindes. Overgives denne parameter ukontrolleret til include, kan en angriber anmode om andre filer på serveren. I det mere harmløse tilfælde læser vedkommende konfigurationsfiler med adgangsdata. I det værre tilfælde får vedkommende PHP til at udføre indhold, som vedkommende forinden har lagt et andet sted, f.eks. i et upload eller en logfil.

For ledelsen er det vigtigt: Denne sårbarhed sidder sjældent i CMS-kernen, men oftest i egenudviklinger, gamle udvidelser eller hurtigt byggede ekstrasider. Den falder ikke i øjnene i hverdagen, fordi websitet fungerer normalt.

Ved Remote File Inclusion indlæser PHP kode fra en fremmed adresse. Det forudsætter, at allow_url_include er aktiveret. I aktuelle PHP-versioner er denne indstilling slået fra som standard, men på gamle eller forkert konfigurerede servere finder man den stadig.

Typiske sårbare mønstre i koden

Udsatte er steder, hvor en værdi fra forespørgslen, fra cookies eller fra databasen bliver en del af en filsti. Hyppige eksempler er sprogskift, der indlæser en sprogfil efter en parameter, sidevalg via en parameter i adressen, valg af skabelon eller tema og download-scripts til dokumenter. En påhæftet .php for enden af stien beskytter her ikke pålideligt, fordi angribere kan vige ud til eksisterende PHP-filer.

Et første overblik får I med en søgning efter indbindinger, der indeholder variabler. Den giver også harmløse fund, men viser, hvor der skal ses nærmere efter:

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

Kontrollér hvert fund for, hvor variablen stammer fra, og om en besøgende kan påvirke den.

Det sikre mønster: tilladelsesliste i stedet for sti fra forespørgslen

Den mest pålidelige beskyttelse er, at den besøgende kun vælger en nøgle, og applikationen selv afgør, hvilken fil der hører til. Stien sammensættes aldrig af input.

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

Dette mønster er kort, let at kontrollere og levner intet spillerum. I moderne frameworks overtager routeren denne opgave; dér bør controllere og skabeloner ligeledes aldrig bestemmes af frie parametre.

Når filnavne skal være dynamiske: realpath og basismappe

Nogle gange er en fast liste ikke praktisk, f.eks. ved downloads fra en dokumentmappe. Så kontrollerer I den opløste sti mod en fast basismappe og tillader kun enkle filnavne.

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

// Udlevér i stedet for at indbinde: readfile() udfører ingen kode.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

To punkter er afgørende. Det regulære udtryk tillader ingen mappeadskillere og ingen specialtegn. Og filer, der kun skal udleveres, læses med readfile(), ikke med include, så indeholdt kode aldrig udføres. str_starts_with() er tilgængelig fra og med PHP 8.0.

Sikring på serversiden: php.ini, open_basedir og rettigheder

Sikker kode er den første forsvarslinje. Serverkonfigurationen sørger for, at en overset fejl gør mindre skade.

; php.ini eller FPM-pool (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; kun hvis applikationen ikke indlæser eksterne URL'er
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

allow_url_fopen har nogle applikationer brug for til opdateringer eller grænseflader. Test fravalget først i et testmiljø. open_basedir begrænser PHP til websitets egne mapper, hvilket er særligt vigtigt på servere med flere kunder. Enkeltheder står i vejledningerne open_basedir og isolation pr. website og Konfigurér php.ini sikkert.

Som supplement bør upload- og cachemapper ikke kunne udføres, og logfiler ikke ligge i webroot. Dermed mangler en angriber de steder, hvor vedkommende kunne lægge eget indhold til en indbinding.

Hvordan I genkender udnyttelsesforsøg i logs

Forsøg på at udnytte en file inclusion efterlader som regel spor i access-loggen. Påfaldende er parametre, der indeholder mappeskift, absolutte systemstier, stream wrappers eller fuldstændige fremmede adresser, især ved parametre som page, file, template eller lang. Et enkelt fund er som regel automatiseret scanning. Vigtigt er, om en sådan forespørgsel blev besvaret med statuskode 200 og usædvanlig svarstørrelse.

Hvordan I går systematisk frem, beskriver Analysér weblogs efter et angreb. Finder I tegn på vellykkede adgange, så gå ud fra, at konfigurationsfiler er læst, og forny de adgangsdata, de indeholder.

Dertil hører først og fremmest databaseadgangskoder, nøgler til betalings- og forsendelsestjenester, SMTP-adgange og CMS'ets hemmelige nøgler. Kontrollér desuden, om der siden den første mistænkelige adgang er opstået nye filer. Den, der kunne læse filer, har måske også forsøgt at lægge egne. I så fald handler det ikke længere kun om en sårbarhed i koden, men om en sikkerhedshændelse, som bør behandles struktureret.

Sikr rettelser varigt

Efter en rettelse betaler det sig at sikre beskyttelsesfunktionen med automatiserede tests. En enkel test overgiver sidevalget ukendte værdier, mappeskift og tomt input og forventer i alle tilfælde standardsiden eller en 404-fejl. Sådanne tests forhindrer, at en senere ændring uset åbner sårbarheden igen.

For ledelse og projektansvarlige er et spørgsmål til bureauet nyttigt: Findes der i applikationen steder, hvor filer indlæses ud fra parametre, og hvordan er de sikret? Et konkret svar med fundsteder og tests er et godt tegn.

Hvordan hjælper PHP SOS konkret?

  • Vi søger målrettet i jeres kode efter include, require og filfunktioner med input fra forespørgslen og vurderer hvert fund.
  • Vi sætter allow_url_include, open_basedir og passende rettigheder pr. website og kontrollerer, at applikationen fortsat fungerer bagefter.
  • Vi analyserer logs for udnyttelsesforsøg og afklarer, om adgangsdata skal fornyes.
  • Til en uafhængig kontrol tilbyder vi en sikkerhedsaudit med penetrationstest til PHP-applikationer.

Ofte stillede spørgsmål

Hvad er forskellen på LFI og RFI?

Ved Local File Inclusion indlæser applikationen en fil, der allerede ligger på serveren, men ikke burde indlæses. Ved Remote File Inclusion hentes kode fra en fremmed adresse. RFI forudsætter en usikker PHP-indstilling, LFI gør ikke.

Er det nok at fjerne ../ fra parameteren?

Nej. Sådanne filtre kan ofte omgås med kodning eller varianter og overser absolutte stier. Sikkert er kun en fast tilknytning af tilladte værdier til filer eller en kontrol af den opløste sti mod en basismappe.

Beskytter open_basedir fuldstændigt mod file inclusion?

Nej, det begrænser kun de mapper, som PHP må tilgå. Inden for disse grænser kan en sårbarhed stadig udnyttes. open_basedir er et ekstra beskyttelseslag og erstatter ikke sikker kode.

Er CMS som WordPress berørt af LFI?

Kernen i gængse CMS regnes på dette punkt for velgennemprøvet. Sårbarheder dukker snarere op i udvidelser, temaer og egenudviklinger. Opdateringer af udvidelserne og et blik på deres sikkerhedsmeddelelser er derfor vigtige.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp