Kort gezegd: Met expose_php = Off in de php.ini verdwijnt de header X-Powered-By: PHP/…. Daarbij horen server_tokens off; in Nginx en ServerTokens Prod en ServerSignature Off in Apache. Dat maakt geen server veiliger, maar ontneemt geautomatiseerde scans een kant-en-klare versielijst. Uw eigen patchstatus controleert u daarna via pakketbeheer en processen, niet via headers.
Het visitekaartje in elk antwoord
Wie na 21 oktober 2026 wilde weten hoeveel servers nog een oude PHP-versie tonen, hoefde niet lang te zoeken. Veel webservers noemen hun PHP-versie in elk afzonderlijk antwoord, bijvoorbeeld als X-Powered-By: PHP/8.2.20. Internetbrede zoekdiensten lezen deze gegevens mee, en Unit 42 van Palo Alto Networks telde voor PHP2Shell meer dan 22,6 miljoen blootgestelde, potentieel kwetsbare instanties.
Voor aanvallers is zo'n vermelding een sluiproute. Ze kunnen doelwitten vooraf sorteren in plaats van blind te proberen. Voor beheerders is ze daarentegen nutteloos, want ze bewijst niet eens de eigen patchstatus: distributies leveren correcties vaak als backport uit zonder nieuw versienummer.
Dit artikel laat zien waar PHP en webserver versie-informatie prijsgeven en hoe u de vermeldingen uitschakelt. Het zegt ook openlijk wat dat oplevert en wat niet.
Waar versiegegevens overal opduiken
De PHP-versie is slechts één van meerdere plaatsen. Een volledige blik loont, omdat één enkele vergeten plek de andere maatregelen waardeloos maakt.
| Vindplaats | Voorbeeld | Uitschakelen via |
|---|---|---|
| HTTP-header van PHP | X-Powered-By: PHP/8.3.x |
expose_php = Off in de php.ini |
| HTTP-header van de webserver | Server: nginx/1.x of Server: Apache/2.4.x (Debian) |
server_tokens off; resp. ServerTokens Prod |
| Foutpagina's van de webserver | Versieregel onder 404- of 500-pagina's | dezelfde instellingen, in Apache aanvullend ServerSignature Off |
| Header van de applicatie | eigen X-Powered-By-vermeldingen van frameworks |
fastcgi_hide_header resp. Header unset |
| Bestanden in de webroot | phpinfo()-testbestanden, readme- en changelogbestanden |
verwijderen of afsluiten |
| PHP-foutmeldingen | Paden en versiedetails in de browser | display_errors = Off |
Testbestanden met phpinfo() zijn daarbij de rijkste bron voor aanvallers. Ze verraden niet alleen de versie, maar de hele configuratie; meer daarover in het artikel phpinfo()-bestanden: waarom ze moeten verdwijnen.
expose_php uitschakelen in de php.ini
Volgens de PHP-handleiding is expose_php standaard ingeschakeld en alleen in de php.ini te wijzigen, niet in de pool, niet via .htaccess en niet tijdens de uitvoering. Stel de waarde daarom in de php.ini in van elke uitvoeringsmodus die websites uitlevert, dus bij Debian en Ubuntu bijvoorbeeld onder /etc/php/<version>/fpm/ en eventueel /etc/php/<version>/apache2/.
; php.ini van de web-SAPI, herstart daarna PHP-FPM resp. Apache
expose_php = Off
Draaien er meerdere PHP-versies parallel, dan heeft elke versie een eigen vermelding nodig. Een herstart van de betreffende service is verplicht, want PHP leest de php.ini alleen bij het opstarten.
Server-headers in Nginx en Apache inkorten
Nginx noemt zijn versie standaard in de Server-header en op foutpagina's. Met server_tokens off; blijft alleen de productnaam over. Daarnaast kan een X-Powered-By-header die de applicatie zelf instelt, met fastcgi_hide_header worden weggefilterd. Volgens de Nginx-documentatie verbergt Nginx uit zichzelf alleen Status en X-Accel-…, niet X-Powered-By.
# in het http-blok, geldt voor alle websites
server_tokens off;
fastcgi_hide_header X-Powered-By;
In Apache bepaalt ServerTokens de Server-header en tegelijk de versieregel onder foutpagina's. De instelling geldt volgens de Apache-documentatie alleen server-breed, niet per VirtualHost. Omdat PHP-FPM-antwoorden via mod_proxy_fcgi in een andere headertabel terechtkomen dan antwoorden van de server zelf, stelt u het verwijderen in beide varianten in.
# server-brede configuratie, bijv. /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
# vereist mod_headers
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
Controleer de configuratie vóór het opnieuw laden met nginx -t respectievelijk apachectl configtest. Hoe u via headers actief bescherming voor bezoekers inschakelt, bijvoorbeeld met HSTS of een Content-Security-Policy, beschrijft de gids Beveiligingsheaders voor websites.
Zo controleert u het resultaat van buitenaf
Controleer na de omschakeling elk domein afzonderlijk, bij voorkeur ook een foutpagina. De volgende opdrachten sturen alleen normale verzoeken naar uw eigen websites:
# Headers van de startpagina
curl -sI https://www.example.de/ | grep -iE '^(server|x-powered-by):'
# Headers van een niet-bestaande pagina
curl -sI https://www.example.de/gibt-es-nicht-4711 | grep -iE '^(server|x-powered-by):'
Verwacht wordt een Server-header zonder versienummer en geen X-Powered-By. Staat er nog steeds een PHP-versie, dan is meestal een andere php.ini actief of is een service nog niet herstart. Staat er een CDN voor de server, controleer dan aanvullend de oorspronkelijke server rechtstreeks, voor zover die bereikbaar is.
Leg de PHP-versie intern toch vast: in uw serverinventaris, met pakketstatus en datum van de laatste controle. De patchstatus bewijst u via de server, zoals beschreven onder PHP-versie en patchstatus juist controleren.
Wat het verbergen oplevert en wat niet
Eerlijk beschouwd is het uitschakelen van versiegegevens een kleine maatregel met weinig inspanning. Ze verlaagt de kans om op te duiken in gerichte zoekacties naar bepaalde versies en vermindert de informatie die een aanvaller zonder moeite krijgt.
Ze beschermt echter niet tegen geautomatiseerde aanvallen die hun verzoeken gewoon naar elke bereikbare server sturen. Hoe zulke massascans verlopen, beschrijft het artikel Massascans naar ongepatcht PHP. Tegen PHP2Shell helpt alleen de update naar PHP 8.5.12, 8.4.27, 8.3.36 of 8.2.35 respectievelijk een bevestigde backport, gevolgd door de herstart van alle PHP-processen.
Een neveneffect is daarentegen bijzonder nuttig: wie versiegegevens naar buiten uitschakelt, moet zijn versies intern netjes vastleggen. In een situatie als PHP2Shell bepaalt juist dat overzicht hoe snel u weet welke servers zijn getroffen.
Zinvol is het verbergen daarom als onderdeel van een basishardening, niet als afzonderlijke maatregel. Het hoort op dezelfde checklist als uitgeschakelde foutuitvoer, verwijderde testbestanden en vergrendelde configuratiewaarden.
Hoe helpt PHP SOS concreet?
- Vindplaatsen inventariseren: wij controleren headers, foutpagina's en webroot van alle domeinen op versiegegevens en vergeten testbestanden.
- Configuratie aanpassen: wij stellen
expose_php, Server-headers en headerfilters in voor elke PHP-versie en elke webserver en herstarten de services gecontroleerd. - Patchstatus intern aantonen: wij documenteren versies en pakketstanden waar ze thuishoren, in de inventaris in plaats van in de HTTP-header.
- In de hardening inpassen: de maatregel maakt deel uit van onze serverhardening voor PHP-webservers.
Veelgestelde vragen
Maakt expose_php = Off mijn server veilig?
Nee. De instelling verwijdert alleen de versievermelding uit de HTTP-header. Een kwetsbare PHP-versie blijft kwetsbaar en geautomatiseerde aanvallen proberen hun verzoeken vaak toch bij elke bereikbare server. U ontneemt aanvallers wel een eenvoudige voorselectie en verlaagt de zichtbaarheid in zoekmachines voor servers.
Kan ik expose_php in de FPM-pool of via .htaccess instellen?
Volgens de PHP-handleiding is expose_php alleen in de php.ini te wijzigen. Stel de waarde daarom in de php.ini van elke web-SAPI in en herstart daarna PHP-FPM of Apache.
Waarom zie ik X-Powered-By ondanks expose_php = Off?
Dan stelt meestal de applicatie of een framework de header zelf in, of is er een andere php.ini actief. Verwijder de header aanvullend in de webserver: met fastcgi_hide_header in Nginx of Header unset in Apache.
Hoe controleer ik mijn patchstatus als de versie niet meer zichtbaar is?
Via de server zelf: pakketbeheer, pakketchangelog met de CVE-nummers en de starttijd van de PHP-processen. De vermelding in de HTTP-header was nooit een bewijs, want distributies voeren backports vaak door zonder nieuw versienummer.