In PHP laden de instructies include en require (en hun varianten _once) een bestand en voeren ze de code daarin uit. Ze worden overal gebruikt, bijvoorbeeld om een template van een thema te laden. Het gevaar ontstaat wanneer het pad van het bestand afhangt van gegevens die een bezoeker zonder voldoende controle meestuurt. De MITRE-catalogus deelt deze zwakte in onder CWE-98, met twee gangbare namen: RFI voor inclusie op afstand, LFI voor lokale inclusie.
Hoe de aanval werkt
Code zoals deze laat de bezoeker kiezen welk bestand er wordt geladen:
// Niet doen
include( __DIR__ . '/templates/' . $_GET['weergave'] . '.php' );
- LFI (Local File Inclusion): met reeksen als
../klimt de aanvaller omhoog in de mappenstructuur en laat hij een bestand laden dat al op de server staat. In het beste geval leest hij een bestand dat hij niet hoort te zien; lukt het hem een bestand te laten includen waarvan hij de inhoud bepaalt (een logbestand, een geüpload bestand), dan krijgt hij remote code execution. - RFI (Remote File Inclusion): de aanvaller geeft een URL naar zijn eigen server op en PHP voegt zijn code direct in. Dat is de meest directe vorm, maar er is een optie voor nodig die zelden aanstaat.

De rol van de PHP-configuratie
De PHP-documentatie is duidelijk over twee instellingen:
allow_url_includestaat URL's toe inincludeenrequire. De standaardwaarde is0, je kunt hem alleen in de systeemconfiguratie (php.ini) wijzigen en hij is verouderd sinds PHP 7.4.0. Hij vereist ook datallow_url_fopenaanstaat.allow_url_fopenmaakt het mogelijk URL's te openen alsof het bestanden zijn; deze optie staat standaard aan, omdat veel scripts haar nodig hebben.
RFI uitschakelen lost niet alles op: met de wrappers van PHP, zoals php://filter, kun je op een standaardconfiguratie sommige LFI's omzetten in het uitvoeren van code, en phar:// werd lange tijd gebruikt om een onveilige deserialisatie te starten. Ons artikel over de wrappers php://filter en phar beschrijft die technieken.
Hoe je je ertegen beschermt
Het beste verweer, dat ook MITRE aanraadt, is nooit een pad op te bouwen uit ontvangen gegevens, maar vaste waarden te koppelen aan bekende bestanden:
$weergaven = array( 'lijst' => 'lijst.php', 'raster' => 'raster.php' );
$weergave = isset( $weergaven[ $_GET['weergave'] ?? '' ] ) ? $weergaven[ $_GET['weergave'] ] : 'lijst.php';
include __DIR__ . '/templates/' . $weergave;
- Houd bestanden die worden ingevoegd waar mogelijk buiten de webroot.
- Beperk met
open_basedirwat PHP mag lezen: een misbruikte inclusie kan dan niet buiten de toegestane mappen komen. PHP harden bij je hostingprovider legt deze instelling en de gevolgen uit. - Een web application firewall blokkeert typische patronen (
../,php://), maar alleen als aanvulling.
Voor WordPress
De WordPress-core bouwt zijn inclusies niet op uit parameters van bezoekers: het risico komt van plugins en thema's die een template, een taal of een module laden op basis van een URL- of AJAX-parameter. Het favoriete doelwit van een LFI is wp-config.php, met de toegangsgegevens van de database en de beveiligingssleutels; een vergeten gevoelig bestand in de root, zoals een .env of een back-up, is een ander makkelijk doelwit, zoals ons artikel over blootgestelde gevoelige bestanden laat zien. Controleer ten slotte of je hostingprovider allow_url_include uitgeschakeld laat.