Aktuellt läge: PHP2Shell. Två kritiska PHP-sårbarheter (CVSS 9,2) tillåter skadlig kod utan inloggning. Patchar sedan den 21 oktober 2026.Vad som bör göras nu →

Förhindra Local File Inclusion i PHP: LFI och RFI

När include eller require tar över sökvägar från förfrågan kan angripare ladda främmande filer. Så bygger ni sidval och mallar säkert och skyddar dessutom servern.

Aktualitet 5 min läsningGuider

Kort sagt: Local File Inclusion i PHP uppstår när include, require eller filfunktioner använder en sökväg som besökaren kan påverka. Den säkra lösningen är en fast tillåtelselista: Parametern väljer bara bland kända värden, själva sökvägen kommer aldrig från förfrågan. På serversidan kompletterar allow_url_include=Off, open_basedir och restriktiva filrättigheter skyddet.

Vad är Local File Inclusion i PHP?

Många äldre PHP-applikationer laddar sidor enligt ett enkelt mönster: En parameter i adressen bestämmer vilken fil som inkluderas. Skickas parametern ogranskad till include kan en angripare begära andra filer på servern. I det mildare fallet läser angriparen konfigurationsfiler med inloggningsuppgifter. I det värre fallet får angriparen PHP att köra innehåll som angriparen tidigare lagt på ett annat ställe, till exempel i en uppladdning eller en loggfil.

För ledningen är det viktigt att veta: Den här sårbarheten finns sällan i CMS-kärnan utan oftast i egenutveckling, gamla tillägg eller snabbt byggda extrasidor. Den märks inte i vardagen, eftersom webbplatsen fungerar normalt.

Vid Remote File Inclusion laddar PHP kod från en främmande adress. Det förutsätter att allow_url_include är aktiverat. I aktuella PHP-versioner är den inställningen avstängd som standard, men på gamla eller felkonfigurerade servrar hittar man den fortfarande.

Typiska sårbara mönster i koden

Utsatta är ställen där ett värde från förfrågan, från cookies eller från databasen blir en del av en filsökväg. Vanliga exempel är språkväljare som laddar en språkfil efter en parameter, sidval via en parameter i adressen, val av mall eller tema och nedladdningsskript för dokument. Ett påhängt .php i slutet av sökvägen skyddar inte tillförlitligt, eftersom angripare kan välja befintliga PHP-filer.

En första överblick får ni med en sökning efter inkluderingar som innehåller variabler. Den ger även ofarliga träffar men visar var man bör titta närmare:

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

Kontrollera varje träff: var kommer variabeln ifrån, och kan en besökare påverka den?

Det säkra mönstret: tillåtelselista i stället för sökväg från förfrågan

Det tillförlitligaste skyddet är att besökaren bara väljer en nyckel och att applikationen själv avgör vilken fil som hör till den. Sökvägen sätts aldrig ihop av indata.

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

Det här mönstret är kort, lätt att granska och lämnar inget spelrum. I moderna ramverk tar routern över den uppgiften; där bör controllers och mallar likaså aldrig bestämmas av fria parametrar.

När filnamn måste vara dynamiska: realpath och baskatalog

Ibland är en fast lista inte praktisk, till exempel vid nedladdningar från en dokumentmapp. Då kontrollerar ni den upplösta sökvägen mot en fast baskatalog och tillåter bara enkla filnamn.

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

// Leverera i stället för att inkludera: readfile() kör ingen kod.
$datei = sichererPfad((string) ($_GET['datei'] ?? ''));
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($datei) . '"');
readfile($datei);

Två punkter är avgörande. Det reguljära uttrycket tillåter inga katalogavgränsare och inga specialtecken. Och filer som bara ska levereras läses med readfile(), inte med include, så att kod som finns i filen aldrig körs. str_starts_with() finns från PHP 8.0.

Skydd på serversidan: php.ini, open_basedir och rättigheter

Säker kod är det första försvaret. Serverkonfigurationen ser till att ett förbisett fel gör mindre skada.

; php.ini eller FPM-pool (php_admin_value / php_admin_flag)
allow_url_include = Off
allow_url_fopen   = Off   ; endast om programmet inte laddar externa URL:er
open_basedir      = /var/www/kunde-a/:/tmp/kunde-a/
display_errors    = Off
log_errors        = On

allow_url_fopen behövs av vissa applikationer för uppdateringar eller gränssnitt. Testa avstängningen först i en testmiljö. open_basedir begränsar PHP till webbplatsens egna kataloger, vilket är särskilt viktigt på servrar med flera kunder. Detaljer finns i guiderna open_basedir och isolering per webbplats och Konfigurera php.ini säkert.

Dessutom bör uppladdnings- och cachemappar inte vara körbara och loggfiler inte ligga i webbroten. Då saknar en angripare de platser där angriparen kunde lägga eget innehåll för en inkludering.

Så känner ni igen utnyttjandeförsök i loggar

Försök att utnyttja en file inclusion lämnar oftast spår i åtkomstloggen. Misstänkta är parametrar som innehåller katalogbyten, absoluta systemsökvägar, stream wrappers eller fullständiga främmande adresser, särskilt vid parametrar som page, file, template eller lang. En enskild träff är oftast automatiserad skanning. Viktigt är om en sådan förfrågan besvarades med statuskod 200 och ovanlig svarsstorlek.

Hur ni går tillväga systematiskt beskriver Analysera webbserverloggar efter ett angrepp. Hittar ni tecken på lyckade åtkomster, utgå från att konfigurationsfiler har lästs och förnya de inloggningsuppgifter som finns i dem.

Dit hör framför allt databaslösenord, nycklar för betal- och fraktjänster, SMTP-åtkomster och CMS:ets hemliga nycklar. Kontrollera dessutom om nya filer har uppstått sedan den första misstänkta åtkomsten. Den som kunde läsa filer har kanske också försökt lägga upp egna. I så fall handlar det inte längre bara om en sårbarhet i koden utan om en säkerhetsincident som bör hanteras strukturerat.

Säkra rättelserna varaktigt

Efter en rättelse lönar det sig att säkra skyddsfunktionen med automatiserade tester. Ett enkelt test lämnar sidvalet okända värden, katalogbyten och tomma indata och förväntar sig i alla fall standardsidan eller ett 404-fel. Sådana tester hindrar att en senare ändring obemärkt öppnar sårbarheten igen.

För ledning och projektansvariga är en fråga till byrån till hjälp: Finns det i applikationen ställen där filer laddas utifrån parametrar, och hur är de skyddade? Ett konkret svar med fyndplatser och tester är ett gott tecken.

Hur hjälper PHP SOS konkret?

  • Vi söker riktat i er kod efter include, require och filfunktioner med indata från förfrågan och bedömer varje fynd.
  • Vi sätter allow_url_include, open_basedir och lämpliga rättigheter per webbplats och kontrollerar att applikationen fortsätter fungera.
  • Vi analyserar loggar efter utnyttjandeförsök och klarlägger om inloggningsuppgifter måste förnyas.
  • För en oberoende granskning erbjuder vi en säkerhetsgranskning med penetrationstest för PHP-applikationer.

Vanliga frågor

Vad är skillnaden mellan LFI och RFI?

Vid Local File Inclusion laddar applikationen en fil som redan ligger på servern men inte borde laddas. Vid Remote File Inclusion hämtas kod från en främmande adress. RFI förutsätter en osäker PHP-inställning, LFI gör det inte.

Räcker det att ta bort ../ ur parametern?

Nej. Sådana filter går ofta att kringgå med kodning eller varianter och missar absoluta sökvägar. Säkert är bara en fast tilldelning av tillåtna värden till filer eller en kontroll av den upplösta sökvägen mot en baskatalog.

Skyddar open_basedir fullständigt mot file inclusion?

Nej, det begränsar bara vilka kataloger PHP får komma åt. Inom de gränserna går en sårbarhet fortfarande att utnyttja. open_basedir är ett extra skyddslager och ersätter inte säker kod.

Berörs CMS som WordPress av LFI?

Kärnan i gängse CMS anses på den punkten vara väl granskad. Sårbarheter dyker snarare upp i tillägg, teman och egenutveckling. Uppdateringar av tilläggen och en titt i deras säkerhetsmeddelanden är därför viktiga.

Källor

Direktkontakt

Varje timme räknas. Skriv till oss nu.

Beskriv kort system, PHP-version och observation. Vi hör av oss, klarlägger läget och arbetar på distans tills incidenten är avslutad och dokumenterad.

Direkthjälp