Kort gezegd: open_basedir beperkt de mappen waartoe PHP toegang heeft. Alleen is dat slechts een extra barrière. Werkzame isolatie per website ontstaat pas in samenspel: eigen systeemgebruiker, eigen PHP-FPM-pool, eigen tmp-map en eigen databasetoegangen. Dan blijft een inbraak op één website beperkt tot die website.
Waarom isolatie na PHP2Shell de schade bepaalt
Op veel servers draaien meerdere websites naast elkaar: de bedrijfssite, een webshop, een oude campagnesite, bij bureaus vaak tientallen klantprojecten. Vaak delen ze één systeemgebruiker en één PHP-proces. Wordt er één gecompromitteerd, dan liggen alle andere open.
PHP2Shell maakt dit risico tastbaar. De kwetsbaarheden CVE-2026-109618 en CVE-2026-109619 maken het mogelijk zonder aanmelding schadelijke code uit te voeren, onafhankelijk van het CMS. Volgens mediaberichten was er al op 17-10-2026 een eerste aanvalspoging, de patches volgden op 21-10. De oplossing is de update. Of een aanval in de tijd daarvoor één of tien websites treft, bepaalt echter de isolatie.
Bij de tweede kwetsbaarheid komt nog een gedachte bij: volgens het PHP-project kan de interne toestand van een verzoek in een worker blijven bestaan en door een later verzoek in dezelfde worker worden gebruikt. Gescheiden pools per website zorgen ervoor dat websites hoe dan ook geen workers delen.
Wat open_basedir doet
Met open_basedir legt u een lijst van mappen vast. Bestandsfuncties van PHP zoals fopen, include of file_get_contents weigeren dan toegang tot alles buiten die lijst. Een binnengebracht script kan zo niet zomaar de configuratiebestanden van de buurwebsite lezen.
De grenzen zijn belangrijk: de controle vindt plaats binnen PHP. Programma's die buiten PHP worden gestart vallen er niet onder en fouten in de interpreter kunnen haar omzeilen. Daarom hoort open_basedir altijd samen met geblokkeerde systeemfuncties, zoals beschreven in de gids disable_functions correct inzetten, en vooral met scheiding op het niveau van het besturingssysteem.
Isolatie per website in vier lagen
Een stevige scheiding bouwt op meerdere lagen. Elke laag vangt op wat de vorige niet kan.
| Laag | Maatregel | Werking |
|---|---|---|
| Besturingssysteem | eigen systeemgebruiker per website | Bestanden van andere websites zijn niet leesbaar |
| PHP-processen | eigen PHP-FPM-pool met eigen socket | geen gedeelde worker, eigen instellingen |
| PHP-configuratie | open_basedir, eigen tmp- en sessiemap |
extra barrière, geen gedeelde tijdelijke bestanden |
| Gegevens | eigen databasegebruiker met rechten alleen op de eigen database | geen toegang tot vreemde klantgegevens |
Bij hoge beschermingsbehoefte, bijvoorbeeld bij webshops met betalingsafhandeling of portalen met gezondheidsgegevens, komen containers of gescheiden servers erbij.
open_basedir in de PHP-FPM-pool configureren
Het volgende voorbeeld toont een pool voor een website met eigen gebruiker seite1. Paden en versienummer past u aan uw systeem aan.
; /etc/php/8.3/fpm/pool.d/seite1.conf
[seite1]
user = seite1
group = seite1
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
php_admin_value[open_basedir] = /var/www/seite1/:/var/www/seite1-tmp/
php_admin_value[upload_tmp_dir] = /var/www/seite1-tmp/
php_admin_value[sys_temp_dir] = /var/www/seite1-tmp/
php_admin_value[session.save_path] = /var/www/seite1-tmp/sessions
php_admin_value[error_log] = /var/log/php/seite1.error.log
php_admin_flag[session.upload_progress.enabled] = off
De laatste regel zet meteen de PHP2Shell-tussenmaatregel van php.net. Ze werkt alleen vanuit pool, php.ini of serverconfiguratie, niet via ini_set() of .user.ini. De mappen maakt u aan met passende rechten:
sudo useradd --system --home /var/www/seite1 --shell /usr/sbin/nologin seite1
sudo mkdir -p /var/www/seite1-tmp/sessions
sudo chown -R seite1:seite1 /var/www/seite1-tmp
sudo chmod 700 /var/www/seite1-tmp
Hoe de rechten in de eigenlijke webmap eruit moeten zien, beschrijft de gids Bestandsrechten op de webserver.
Webserver koppelen en resultaat controleren
In Nginx verwijst elke website naar haar eigen socket. Zo komt geen verzoek terecht in de pool van een andere website.
server {
server_name seite1.example;
root /var/www/seite1/public;
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/seite1.sock;
}
}
Meer aanwijzingen over deze combinatie vindt u onder Nginx met PHP-FPM beveiligen. Na de herstart controleert u of de pools echt gescheiden draaien:
sudo systemctl restart php8.3-fpm
# Elke pool hoort onder zijn eigen gebruiker te draaien
ps -eo user,pid,cmd | grep "[p]hp-fpm: pool"
Test vervolgens alle functies van de website: uploads, beeldverwerking, caches, geplande taken. Foutmeldingen met de vermelding open_basedir restriction in het foutlog laten zien welk pad nog ontbreekt. Vul alleen paden aan die de toepassing echt nodig heeft, en nooit het hele bestandssysteem.
Bureaus met veel klantsites moeten de poolconfiguratie als sjabloon onderhouden. Zo krijgt elke nieuwe website de scheiding automatisch, in plaats van dat ze later moet worden nagerust. Achtergronden voor dit geval staan onder Beveiligingspartner voor bureaus.
Typische valkuilen bij de omschakeling
De omschakeling naar gescheiden pools is plannen, maar kent enkele terugkerende valkuilen. De meest voorkomende betreft gedeelde bibliotheken: ligt bijvoorbeeld een framework of een map met lettertypen buiten de websitemap, dan moet dat pad leesbaar in open_basedir worden opgenomen. Beter is het zulke afhankelijkheden in het project zelf binnen te halen.
De tweede valkuil zijn sessies. Verandert de opslaglocatie, dan zijn alle bezoekers één keer afgemeld en gaan lopende winkelmandjes verloren. Plan de omschakeling daarom in een rustig tijdvenster en kondig haar intern aan.
Ten derde lopen geplande taken vaak via de opdrachtregel en dus onder een andere gebruiker dan de website. Controleer cronjobs en wachtrijen en laat ze onder de nieuwe websitegebruiker draaien, anders ontstaan bestanden met de verkeerde eigenaar die PHP later niet meer mag wijzigen.
Tot slot moet elke pool eigen grenzen voor processen en geheugen hebben. Een website die onder belasting komt of wordt aangevallen, kan zo de andere niet mee op de knieën dwingen.
Hoe helpt PHP SOS concreet?
- We inventariseren welke websites nu gebruikers, processen en databases delen.
- We richten per website eigen gebruikers, pools, tmp-mappen en databasetoegangen in, zonder de toepassingen te wijzigen.
- We testen elke website na de omschakeling en verhelpen ontbrekende paden gericht.
- We documenteren de scheiding als sjabloon voor toekomstige projecten.
Hoe dat in een totaalconcept past, beschrijft de dienst Serververharding voor PHP-webservers.
Veelgestelde vragen
Volstaat open_basedir om websites van elkaar te scheiden?
Nee. open_basedir is een extra barrière binnen PHP, geen harde scheiding. Betrouwbaar wordt de isolatie pas met eigen systeemgebruikers en pools per website, bij hogere beschermingsbehoefte met containers of gescheiden servers.
Waarom werken uploads niet meer nadat ik open_basedir heb ingesteld?
Meestal ontbreekt de map voor tijdelijke bestanden in de lijst. Maak voor elke website een eigen tmp-map aan, neem die op in open_basedir en zet upload_tmp_dir en sys_temp_dir op deze map.
Kan een toepassing open_basedir zelf opheffen?
Een toepassing kan de instelling tijdens de uitvoering alleen verder beperken, niet versoepelen. Stel open_basedir toch in via php_admin_value in de pool, zodat de waarde eenduidig vastligt.
Is isolatie ook mogelijk bij shared hosting?
Dat ligt bij de hoster. Veel aanbieders scheiden klanten via eigen gebruikers en PHP-processen. Vraag na hoe de scheiding is uitgevoerd, vooral als meerdere van uw websites in één pakket zitten.