Open het netwerktabblad van uw browser op een willekeurige op PHP gebaseerde website en bekijk de responsiekopteksten voor het hoofd-HTML-document. Op veel installaties vindt u een koptekst die er ongeveer zo uitziet: X-Powered-By: PHP/8.1.27. Dat is PHP die behulpzaam aan het hele internet vertelt welke versie er draait. Het is een klein detail dat de meeste site-eigenaren nooit opmerken, maar het blijkt een van de gemakkelijkere stukjes informatie te zijn die een aanvaller verzamelt voordat hij beslist of een site het waard is om verder te onderzoeken.
Deze gids legt uit waarom de koptekst überhaupt bestaat, wat hij daadwerkelijk blootlegt en elke realistische manier om hem kwijt te raken. Van de serverconfiguratie tot het niveau van een enkele WordPress-site op shared hosting waar u de php.ini niet kunt aanraken.
Wat de koptekst een aanvaller daadwerkelijk vertelt
Een waarde zoals PHP/8.1.27 onthult twee nuttige feiten. Ten eerste de hoofdversie. Als u nog op PHP 7.4 of PHP 8.0 zit, die beide het einde van hun levensduur hebben bereikt, weet een aanvaller meteen dat er geen beveiligingspatches meer zullen komen. Ten tweede het exacte patchniveau. Tussen elke twee patchreleases zijn er meestal een handvol publiekelijk bekende CVE's. Een scanner kan uw gemelde versie vergelijken met zijn CVE-database en in milliseconden beslissen of hij blijft prikken of doorgaat.
De versie verbergen patcht uiteraard niets. Als uw PHP verouderd is, is het nog steeds verouderd. Maar de uitzending verwijderen doet drie concrete dingen: het stopt geautomatiseerde bulkscanners ervan om uw site als een goedkoop doelwit te markeren, het maakt handmatige verkenning iets duurder, en het verwijdert een stuk informatie dat simpelweg niets te zoeken heeft in uw responsiekopteksten. Er is geen legitieme reden voor het openbare internet om uw PHP-patchniveau te kennen.
Sommige nalevingskaders en beveiligingschecklists (PCI-DSS, BSI IT-Grundschutz, interne audits in grotere bedrijven) vragen expliciet om deze koptekst te onderdrukken. Zelfs als u niet in een van die contexten werkt, is het een vijfminutige oplossing met geen nadeel.
Waar komt de koptekst vandaan?
De koptekst X-Powered-By wordt door PHP zelf uitgezonden, niet door uw webserver. Het gedrag wordt bestuurd door een enkele php.ini-richtlijn genaamd expose_php. Wanneer die richtlijn is ingesteld op On (wat de standaard is in de meeste PHP-distributies), voegt PHP de koptekst automatisch toe aan elke respons. Schakel het uit en de koptekst verdwijnt voor elke site op die PHP-installatie.
Daarnaast voegen sommige frameworks of toepassingen hun eigen X-Powered-By-waarden toe. Express, ASP.NET en anderen doen dit. WordPress zelf doet dat niet, maar plug-ins doen dat soms wel. Dus nadat u de versievermelding van PHP heeft uitgeschakeld, is het de moeite waard om de responsiekopteksten nog een keer te controleren om te zien of er nog iets uitlekt.
Optie 1: Schakel expose_php uit in php.ini
Dit is de schoonste oplossing als u de server beheert. Open uw php.ini-bestand. Op Linux is het pad meestal een van deze:
/etc/php/8.3/fpm/php.inivoor PHP-FPM, de meest voorkomende setup achter nginx en moderne Apache/etc/php/8.3/apache2/php.inivoor Apache met mod_php/etc/php/8.3/cli/php.inivoor de commandoregel, waar u zich in deze context meestal niet om bekommert
Het versienummer in het pad komt overeen met welke PHP u gebruikt. Zoek de regel die luidt:
expose_php = OnVerander het in:
expose_php = OffSla het bestand op en herstart het PHP-proces zodat de wijziging van kracht wordt. Voor PHP-FPM ziet dat er zo uit:
sudo systemctl restart php8.3-fpmVoor Apache met mod_php:
sudo systemctl restart apache2Om te verifiëren, voer een snelle curl uit tegen uw site en bekijk de kopteksten:
curl -I https://uwdomein.comDe regel X-Powered-By moet volledig verdwenen zijn. Als deze er nog is, heeft u het verkeerde php.ini-bestand bewerkt (er is vaak meer dan één). Controleer welke daadwerkelijk wordt geladen met php --ini op de commandoregel, of door tijdelijk een phpinfo()-aanroep op de site te plaatsen (en deze meteen daarna te verwijderen, alstublieft).
Optie 2: Stel expose_php per site in via .user.ini
Niet iedereen heeft toegang tot de globale php.ini. Op veel shared hosts kunt u nog steeds PHP-instellingen beïnvloeden via een bestand genaamd .user.ini, dat u in de documentroot van uw site plaatst. Maak (of bewerk) een .user.ini met:
expose_php = OffPHP controleert dit bestand bij elk verzoek, maar cachet het resultaat standaard enkele minuten (gecontroleerd door user_ini.cache_ttl, meestal 300 seconden). Geef het dus vijf minuten, wis eventuele edge-caches en controleer vervolgens uw kopteksten opnieuw.
Een woord van voorzichtigheid: niet alle hosts staan toe dat expose_php wordt overschreven vanuit .user.ini. De richtlijn heeft de modus PHP_INI_PERDIR, die dit technisch toestaat, maar sommige hosts whitelisten expliciet wat kan worden gewijzigd. Als de instelling na enkele minuten geen effect heeft, blokkeert uw host deze waarschijnlijk. Ga naar Optie 5.
Optie 3: Verwijder de koptekst in Apache
U kunt de koptekst ook strippen op het webserverniveau, wat werkt ongeacht wat PHP intern doet. Voeg in uw Apache-configuratie (of in de .htaccess van de site, als AllowOverride dit toestaat) toe:
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>De reden om zowel unset als always unset te gebruiken, is dat de reguliere versie alleen geldt voor succesvolle 2xx-responsies. De always-variant is ook van toepassing op foutresponsies zoals 500-pagina's, wat precies de plek is waar u ook niet wilt dat de versie uitlekt.
mod_headers moet zijn ingeschakeld om dit te laten werken. Op Debian en Ubuntu:
sudo a2enmod headers
sudo systemctl reload apache2Als u op shared hosting met Apache zit, werkt de .htaccess-variant bijna altijd, omdat de meeste hosters mod_headers inschakelen en het toestaan via AllowOverride All. Als de regel geen effect heeft, vraag uw host of mod_headers beschikbaar is.
Optie 4: Verwijder de koptekst in nginx
Op nginx gaat het equivalent in het server-blok van uw site, of in een algemeen http-blok als u het sitebreed wilt:
more_clear_headers 'X-Powered-By';Klein voorbehoud: more_clear_headers vereist de headers-more-nginx-module, die niet op elke distributie deel uitmaakt van het standaard nginx-pakket. Debian en Ubuntu leveren dit in het nginx-extras-pakket:
sudo apt install nginx-extrasAls u vastzit op kale nginx zonder de extras-module, is er een omweg met fastcgi_hide_header. Dit is eigenlijk het juiste hulpmiddel als de koptekst van PHP-FPM komt (wat in de meeste gevallen zo is):
location ~ \.php$ {
# your usual fastcgi_pass and params
fastcgi_hide_header X-Powered-By;
}Herlaad nginx met sudo nginx -t && sudo systemctl reload nginx en verifieer met curl -I.
Optie 5: Speciaal geval, WordPress
WordPress zelf stelt X-Powered-By niet in. De koptekst komt van PHP. Dus alles hierboven is ongewijzigd van toepassing: het uitschakelen van expose_php of het strippen van de koptekst in Apache of nginx lost het ook op voor een WordPress-site. Maar WordPress geeft u twee extra invalshoeken die de moeite waard zijn om te kennen.
Onderdruk de koptekst vanuit WordPress. Als u geen toegang heeft tot de webserverconfiguratie en .user.ini niet werkt op uw host, kunt u de koptekst programmatisch laten vallen via een must-use-plug-in. Maak een bestand op wp-content/mu-plugins/remove-powered-by.php (maak de map mu-plugins aan als deze nog niet bestaat) en plaats dit erin:
<?php
/**
* Plugin Name: Remove X-Powered-By
* Description: Strips the X-Powered-By header from every WordPress response.
*/
if (!defined('ABSPATH')) {
exit;
}
add_action('send_headers', function () {
if (function_exists('header_remove')) {
header_remove('X-Powered-By');
}
});Twee dingen om u bewust van te zijn met deze aanpak. Ten eerste werkt header_remove() alleen als PHP de body van de respons nog niet is gaan verzenden. De send_headers-hook wordt op het juiste moment afgevuurd voor elke normale WordPress-pagina, dus dit werkt voor berichten, pagina's, admin en de REST API. Het helpt niet voor verzoeken die WordPress nooit bereiken, zoals directe aanroepen naar statische bestanden of in cache opgeslagen pagina's die door een reverse proxy worden geserveerd. Ten tweede draaien sommige hosts een reverse proxy (Cloudflare, Varnish, Nginx voor Apache) die de koptekst leest uit het backend-antwoord en deze vervolgens ongewijzigd doorstuurt. Als de koptekst nog steeds in uw browser verschijnt na het installeren van deze plug-in, cachet de proxy hem. Wis de cache en, idealiter, strip de koptekst ook op het proxy-niveau.
WordPress legt ook zijn eigen versie bloot. Terwijl u toch bezig bent, wilt u waarschijnlijk ook omgaan met de tag <meta name="generator" content="WordPress X.Y.Z"> die WordPress in de HTML-head plaatst, en de ?ver=X.Y.Z-parameters op CSS- en JS-bestanden. Die zijn niet hetzelfde als de PHP-versie-koptekst, maar lekken wel de exacte WordPress-versie, wat vergelijkbaar nuttig is voor een aanvaller. Het onderstaande fragment behandelt beide:
<?php
// Remove the generator meta tag
remove_action('wp_head', 'wp_generator');
// Strip the WordPress version from RSS feeds, admin, etc.
add_filter('the_generator', '__return_empty_string');
// Remove ?ver=X.Y.Z from CSS and JS file URLs
add_filter('style_loader_src', function ($src) {
return remove_query_arg('ver', $src);
}, 9999);
add_filter('script_loader_src', function ($src) {
return remove_query_arg('ver', $src);
}, 9999);Merk op dat het strippen van de ?ver=-parameter een neveneffect heeft: de browser kan niet langer alleen op basis van de URL bepalen wanneer een CSS- of JS-bestand is gewijzigd. Als u daarop vertrouwt voor cache-busting, laat het filter dan weg of vervang ver door een hash van de bestandsinhoud.
Optie 6: Cloudflare, Sucuri en andere reverse proxies
Als u achter Cloudflare of een vergelijkbare CDN zit, kunt u de koptekst nog een laag verder strippen, wat fijn is omdat het elke site dekt die u via dezelfde zone routeert zonder de origin aan te raken. In Cloudflare gebeurt dit via een Transform Rule van het type "Modify Response Header":
- Regelnaam: "Remove X-Powered-By"
- Wanneer inkomende verzoeken overeenkomen:
Hostname equals uwdomein.com(of een wildcard als u zonebreed wilt) - Dan: Verwijder koptekst
X-Powered-By
Sucuri, BunnyCDN, Fastly en de meeste andere reverse proxies bieden een equivalent. De exacte bewoording in het dashboard varieert, maar de functie die u zoekt is altijd "modify response headers" of "edge rules".
Andere kopteksten die de moeite waard zijn om te controleren terwijl u toch bezig bent
PHP is niet het enige dat de neiging heeft om luid over zichzelf te zijn in responsiekopteksten. Terwijl u curl open heeft, scan de kopteksten op een van de volgende:
Server: Apache/2.4.58 (Ubuntu)onthult Apache's patch-versie en uw OS-smaak. Onderdruk viaServerTokens ProdenServerSignature Offin Apache, ofserver_tokens offin nginx.X-Powered-CMS,X-Generator,X-Drupal-Cacheof vergelijkbaar. Meestal ingesteld door plug-ins of CMS-specifieke modules. Verwijder op dezelfde manier alsX-Powered-By.X-AspNet-VersionofX-AspNetMvc-Version. Alleen relevant als iets in uw stack .NET aanraakt, maar de moeite waard om te kennen.
InspectWP signaleert al deze in het beveiligingskopteksten-gedeelte van uw rapport. Zodra u de PHP-versie heeft verborgen, is een nieuwe scan uitvoeren de snelste manier om te zien welke andere kleine weggevertjes nog op de lijn staan.
Verifieer en u bent klaar
Na welke route u ook heeft gekozen, doe één laatste controle:
- Open een terminal en voer
curl -I https://uwdomein.comuit. - Bekijk de uitvoer. Er mag helemaal geen regel
X-Powered-Bymeer zijn. - Herhaal voor een admin-URL (probeer voor WordPress
wp-login.php) en voor een foutpagina (voeg een willekeurige string toe aan de URL om een 404 te triggeren). De koptekst moet overal verdwenen blijven. - Als u Cloudflare of een cache gebruikt, test dan ook vanaf een vers IP of met cache-bypass, zodat u weet dat u naar een live respons kijkt en niet naar een gecacheerde.
- Voer een nieuwe InspectWP-scan uit. De PHP-versiecontrole in het Hosting-gedeelte zal nu terugvallen op andere detectiemethoden of de versie markeren als niet onthuld, wat is wat u wilt.
De PHP-versie verbergen is geen vervanging voor het up-to-date houden van PHP. Het is één kleine stap in een groter hardening-plaatje. Maar het is het soort snelle winst dat vijf minuten kost, één gratis stuk informatie verwijdert dat aanvallers anders voor niets verzamelen, en u precies nul kost in ruil.