Kort sagt: Med expose_php = Off i php.ini forsvinder headeren X-Powered-By: PHP/…. Hertil hører server_tokens off; i Nginx samt ServerTokens Prod og ServerSignature Off i Apache. Det gør ingen server mere sikker, men fratager automatiserede scanninger en færdig versionsliste. Jeres egen patch-status kontrollerer I derefter via pakkehåndtering og processer, ikke via headere.
Visitkortet i hvert svar
Den, der efter den 21. oktober 2026 ville vide, hvor mange servere der stadig viser en gammel PHP-version, behøvede ikke at lede længe. Mange webservere nævner deres PHP-version i hvert eneste svar, f.eks. som X-Powered-By: PHP/8.2.20. Søgetjenester på tværs af internettet læser disse angivelser med, og Unit 42 fra Palo Alto Networks talte for PHP2Shell mere end 22,6 millioner eksponerede, potentielt sårbare instanser.
For angribere er en sådan angivelse en genvej. De kan forsortere mål i stedet for at prøve blindt. For driftsansvarlige er den derimod ubrugelig, for den beviser ikke engang den egen patch-status: Distributioner leverer ofte rettelser som backport uden nyt versionsnummer.
Dette indlæg viser, hvor PHP og webserver afslører versionsoplysninger, og hvordan I slår angivelserne fra. Det siger også åbent, hvad det giver, og hvad ikke.
Hvor versionsangivelser overalt dukker op
PHP-versionen er kun ét af flere steder. Et fuldstændigt overblik er umagen værd, fordi et eneste glemt sted devaluerer de andre foranstaltninger.
| Fundsted | Eksempel | Slå fra via |
|---|---|---|
| HTTP-header fra PHP | X-Powered-By: PHP/8.3.x |
expose_php = Off i php.ini |
| HTTP-header fra webserveren | Server: nginx/1.x eller Server: Apache/2.4.x (Debian) |
server_tokens off; hhv. ServerTokens Prod |
| Webserverens fejlsider | versionslinje under 404- eller 500-sider | de samme indstillinger, i Apache desuden ServerSignature Off |
| Header fra applikationen | frameworks' egne X-Powered-By-angivelser |
fastcgi_hide_header hhv. Header unset |
| Filer i webroden | phpinfo()-testfiler, readme- og changelog-filer |
slet eller spær |
| PHP-fejlmeddelelser | stier og versionsdetaljer i browseren | display_errors = Off |
Testfiler med phpinfo() er her den mest givtige kilde for angribere. De afslører ikke kun versionen, men hele konfigurationen; mere herom i indlægget phpinfo()-filer: Hvorfor de skal væk.
Slå expose_php fra i php.ini
Ifølge PHP-manualen er expose_php som standard slået til og kan kun ændres i php.ini, ikke i poolen, ikke via .htaccess og ikke under kørslen. Sæt derfor værdien i php.ini for hver driftsform, der leverer websites, altså ved Debian og Ubuntu for eksempel under /etc/php/<version>/fpm/ og eventuelt /etc/php/<version>/apache2/.
; php.ini for web-SAPI'en, genstart derefter PHP-FPM hhv. Apache
expose_php = Off
Kører flere PHP-versioner parallelt, kræver hver sin post. En genstart af den pågældende tjeneste er obligatorisk, for PHP læser kun php.ini ved start.
Forkort Server-headeren i Nginx og Apache
Nginx nævner som standard sin version i Server-headeren og på fejlsider. Med server_tokens off; bliver kun produktnavnet tilbage. Desuden kan en X-Powered-By-header, som applikationen selv sætter, filtreres væk med fastcgi_hide_header. Ifølge Nginx-dokumentationen skjuler Nginx af sig selv kun Status og X-Accel-…, ikke X-Powered-By.
# i http-blokken, gælder for alle websites
server_tokens off;
fastcgi_hide_header X-Powered-By;
I Apache styrer ServerTokens Server-headeren og samtidig versionslinjen under fejlsider. Indstillingen gælder ifølge Apache-dokumentationen kun serverdækkende, ikke pr. VirtualHost. Fordi PHP-FPM-svar via mod_proxy_fcgi havner i en anden header-tabel end svar fra serveren selv, sætter I fjernelsen i begge varianter.
# serverdækkende konfiguration, f.eks. /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
# kræver mod_headers
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
Kontrollér konfigurationen før genindlæsningen med nginx -t henholdsvis apachectl configtest. Hvordan I via headere aktivt slår beskyttelse til for besøgende, f.eks. med HSTS eller en Content-Security-Policy, beskriver vejledningen Sikkerhedsheadere til websites.
Sådan kontrollerer I resultatet udefra
Kontrollér efter omstillingen hvert domæne for sig, helst også en fejlside. De følgende kommandoer sender kun normale forespørgsler til jeres egne websites:
# Headere på forsiden
curl -sI https://www.example.de/ | grep -iE '^(server|x-powered-by):'
# Headere på en side, der ikke findes
curl -sI https://www.example.de/gibt-es-nicht-4711 | grep -iE '^(server|x-powered-by):'
Forventet er en Server-header uden versionsnummer og ingen X-Powered-By. Står der fortsat en PHP-version, er som regel en anden php.ini aktiv, eller en tjeneste er endnu ikke genstartet. Ligger et CDN foran serveren, kontrollerer I desuden origin-serveren direkte, for så vidt den kan nås.
Notér alligevel PHP-versionen internt: i jeres serverinventar, med pakketilstand og dato for sidste kontrol. Patch-status dokumenterer I via serveren, som beskrevet under Kontrollér PHP-version og patch-status rigtigt.
Hvad skjulningen giver, og hvad ikke
Ærligt indordnet er frakoblingen af versionsangivelser en lille foranstaltning med ringe indsats. Den sænker sandsynligheden for at dukke op i målrettede søgninger efter bestemte versioner og mindsker de oplysninger, en angriber får uden besvær.
Men den beskytter ikke mod automatiserede angreb, der blot sender deres forespørgsler til hver tilgængelig server. Hvordan sådanne massescanninger forløber, beskriver indlægget Massescanninger efter upatchet PHP. Mod PHP2Shell hjælper kun opdateringen til PHP 8.5.12, 8.4.27, 8.3.36 eller 8.2.35 henholdsvis en bekræftet backport, efterfulgt af genstart af alle PHP-processer.
En bivirkning er derimod ganske nyttig: Den, der slår versionsangivelser fra udadtil, må registrere sine versioner ordentligt internt. I en situation som PHP2Shell afgør netop dette overblik, hvor hurtigt I ved, hvilke servere der er berørt.
Fornuftigt er skjulningen derfor som led i en grundlæggende hærdning, ikke som enkeltforanstaltning. Den hører med på den samme tjekliste som slukkede fejludskrifter, slettede testfiler og låste konfigurationsværdier.
Hvordan hjælper PHP SOS konkret?
- Registrér fundsteder: Vi kontrollerer headere, fejlsider og webrod på alle domæner for versionsangivelser og glemte testfiler.
- Tilpas konfigurationen: Vi sætter
expose_php, Server-headere og header-filtre i hver PHP-version og hver webserver og genstarter tjenesterne kontrolleret. - Dokumentér patch-status internt: Vi dokumenterer versioner og pakketilstande dér, hvor de hører hjemme, i inventaret i stedet for i HTTP-headeren.
- Indbyg i hærdningen: Foranstaltningen er en del af vores serverhærdning for PHP-webservere.
Ofte stillede spørgsmål
Gør expose_php = Off min server sikker?
Nej. Indstillingen fjerner kun versionsangivelsen fra HTTP-headeren. En sårbar PHP-version forbliver sårbar, og automatiserede angreb prøver ofte alligevel deres forespørgsler på hver tilgængelig server. Men I fratager angribere en enkel forhåndsudvælgelse og mindsker synligheden i søgemaskiner for servere.
Kan jeg sætte expose_php i FPM-poolen eller via .htaccess?
Ifølge PHP-manualen kan expose_php kun ændres i php.ini. Sæt derfor værdien i php.ini for hver web-SAPI, og genstart derefter PHP-FPM eller Apache.
Hvorfor ser jeg X-Powered-By trods expose_php = Off?
Så sætter som regel applikationen eller et framework headeren selv, eller også er en anden php.ini aktiv. Fjern headeren desuden i webserveren: med fastcgi_hide_header i Nginx eller Header unset i Apache.
Hvordan kontrollerer jeg min patch-status, når versionen ikke længere er synlig?
Via serveren selv: pakkehåndtering, pakkens changelog med CVE-numrene og starttidspunktet for PHP-processerne. Angivelsen i HTTP-headeren var alligevel intet bevis, for distributioner indspiller ofte backports uden nyt versionsnummer.