Kurz gesagt: Mit expose_php = Off in der php.ini verschwindet der Header X-Powered-By: PHP/…. Dazu gehören server_tokens off; in Nginx sowie ServerTokens Prod und ServerSignature Off in Apache. Das macht keinen Server sicherer, nimmt automatisierten Scans aber eine fertige Versionsliste. Den eigenen Patchstand prüfen Sie danach über Paketverwaltung und Prozesse, nicht über Header.
Die Visitenkarte in jeder Antwort
Wer nach dem 21. Oktober 2026 wissen wollte, wie viele Server noch eine alte PHP-Version zeigen, musste nicht lange suchen. Viele Webserver nennen ihre PHP-Version in jeder einzelnen Antwort, etwa als X-Powered-By: PHP/8.2.20. Internetweite Suchdienste lesen diese Angaben mit, und Unit 42 von Palo Alto Networks zählte für PHP2Shell mehr als 22,6 Millionen exponierte, potenziell verwundbare Instanzen.
Für Angreifer ist eine solche Angabe eine Abkürzung. Sie können Ziele vorsortieren, statt blind zu probieren. Für Betreiber ist sie dagegen nutzlos, denn sie belegt nicht einmal den eigenen Patchstand: Distributionen liefern Korrekturen oft als Backport ohne neue Versionsnummer aus.
Dieser Beitrag zeigt, wo PHP und Webserver Versionsinformationen preisgeben und wie Sie die Angaben abstellen. Er sagt auch offen, was das bringt und was nicht.
Wo Versionsangaben überall auftauchen
Die PHP-Version ist nur eine von mehreren Stellen. Ein vollständiger Blick lohnt, weil eine einzige vergessene Stelle die anderen Maßnahmen entwertet.
| Fundstelle | Beispiel | Abstellen über |
|---|---|---|
| HTTP-Header von PHP | X-Powered-By: PHP/8.3.x |
expose_php = Off in der php.ini |
| HTTP-Header des Webservers | Server: nginx/1.x oder Server: Apache/2.4.x (Debian) |
server_tokens off; bzw. ServerTokens Prod |
| Fehlerseiten des Webservers | Versionszeile unter 404- oder 500-Seiten | dieselben Einstellungen, in Apache zusätzlich ServerSignature Off |
| Header der Anwendung | eigene X-Powered-By-Angaben von Frameworks |
fastcgi_hide_header bzw. Header unset |
| Dateien im Webroot | phpinfo()-Testdateien, Readme- und Changelog-Dateien |
löschen oder sperren |
| PHP-Fehlermeldungen | Pfade und Versionsdetails im Browser | display_errors = Off |
Testdateien mit phpinfo() sind dabei die ergiebigste Quelle für Angreifer. Sie verraten nicht nur die Version, sondern die gesamte Konfiguration; mehr dazu im Beitrag phpinfo()-Dateien: Warum sie verschwinden müssen.
expose_php in der php.ini abschalten
Laut PHP-Handbuch ist expose_php standardmäßig eingeschaltet und nur in der php.ini änderbar, nicht im Pool, nicht per .htaccess und nicht zur Laufzeit. Setzen Sie den Wert deshalb in der php.ini jeder Betriebsart, die Websites ausliefert, also bei Debian und Ubuntu zum Beispiel unter /etc/php/<version>/fpm/ und gegebenenfalls /etc/php/<version>/apache2/.
; php.ini der Web-SAPI, danach PHP-FPM bzw. Apache neu starten
expose_php = Off
Laufen mehrere PHP-Versionen parallel, braucht jede ihren Eintrag. Ein Neustart des jeweiligen Dienstes ist Pflicht, denn PHP liest die php.ini nur beim Start.
Server-Header in Nginx und Apache kürzen
Nginx nennt seine Version standardmäßig im Server-Header und auf Fehlerseiten. Mit server_tokens off; bleibt nur der Produktname. Zusätzlich lässt sich ein X-Powered-By-Header, den die Anwendung selbst setzt, mit fastcgi_hide_header herausfiltern. Laut Nginx-Dokumentation blendet Nginx von sich aus nur Status und X-Accel-… aus, nicht X-Powered-By.
# im http-Block, gilt für alle Websites
server_tokens off;
fastcgi_hide_header X-Powered-By;
In Apache steuert ServerTokens den Server-Header und zugleich die Versionszeile unter Fehlerseiten. Die Einstellung gilt laut Apache-Dokumentation nur serverweit, nicht je VirtualHost. Weil PHP-FPM-Antworten über mod_proxy_fcgi in einer anderen Header-Tabelle landen als Antworten des Servers selbst, setzen Sie das Entfernen in beiden Varianten.
# serverweite Konfiguration, z. B. /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
# benötigt mod_headers
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
Prüfen Sie die Konfiguration vor dem Neuladen mit nginx -t beziehungsweise apachectl configtest. Wie Sie über Header aktiv Schutz für Besucher einschalten, etwa mit HSTS oder einer Content-Security-Policy, beschreibt der Ratgeber Sicherheits-Header für Websites.
So prüfen Sie das Ergebnis von außen
Prüfen Sie nach der Umstellung jede Domain einzeln, möglichst auch eine Fehlerseite. Die folgenden Befehle senden nur normale Anfragen an Ihre eigenen Websites:
# Header der Startseite
curl -sI https://www.example.de/ | grep -iE '^(server|x-powered-by):'
# Header einer nicht vorhandenen Seite
curl -sI https://www.example.de/gibt-es-nicht-4711 | grep -iE '^(server|x-powered-by):'
Erwartet wird ein Server-Header ohne Versionsnummer und kein X-Powered-By. Steht dort weiterhin eine PHP-Version, ist meist eine andere php.ini aktiv oder ein Dienst noch nicht neu gestartet. Liegt ein CDN vor dem Server, prüfen Sie zusätzlich den Ursprungsserver direkt, soweit er erreichbar ist.
Halten Sie die PHP-Version intern trotzdem fest: in Ihrem Server-Inventar, mit Paketstand und Datum der letzten Prüfung. Den Patchstand belegen Sie über den Server, wie unter PHP-Version und Patchstand richtig prüfen beschrieben.
Was das Verbergen bringt und was nicht
Ehrlich eingeordnet ist das Abschalten von Versionsangaben eine kleine Maßnahme mit geringem Aufwand. Sie senkt die Wahrscheinlichkeit, in gezielten Suchen nach bestimmten Versionen aufzutauchen, und verringert die Informationen, die ein Angreifer ohne Mühe bekommt.
Sie schützt aber nicht vor automatisierten Angriffen, die ihre Anfragen einfach an jeden erreichbaren Server schicken. Wie solche Massenscans ablaufen, beschreibt der Beitrag Massenscans nach ungepatchtem PHP. Gegen PHP2Shell hilft nur das Update auf PHP 8.5.12, 8.4.27, 8.3.36 oder 8.2.35 beziehungsweise ein bestätigter Backport, gefolgt vom Neustart aller PHP-Prozesse.
Ein Nebeneffekt ist dagegen ausgesprochen nützlich: Wer Versionsangaben nach außen abschaltet, muss seine Versionen intern sauber erfassen. In einer Lage wie PHP2Shell entscheidet genau diese Übersicht darüber, wie schnell Sie wissen, welche Server betroffen sind.
Sinnvoll ist das Verbergen deshalb als Teil einer Grundhärtung, nicht als Einzelmaßnahme. Es gehört in dieselbe Checkliste wie abgeschaltete Fehlerausgaben, gelöschte Testdateien und gesperrte Konfigurationswerte.
Wie hilft PHP SOS konkret?
- Fundstellen erfassen: Wir prüfen Header, Fehlerseiten und Webroot aller Domains auf Versionsangaben und vergessene Testdateien.
- Konfiguration anpassen: Wir setzen
expose_php, Server-Header und Header-Filter in jeder PHP-Version und jedem Webserver und starten die Dienste kontrolliert neu. - Patchstand intern belegen: Wir dokumentieren Versionen und Paketstände dort, wo sie hingehören, im Inventar statt im HTTP-Header.
- In die Härtung einbetten: Die Maßnahme ist Teil unserer Server-Härtung für PHP-Webserver.
Häufige Fragen
Macht expose_php = Off meinen Server sicher?
Nein. Die Einstellung entfernt nur die Versionsangabe aus dem HTTP-Header. Eine verwundbare PHP-Version bleibt verwundbar, und automatisierte Angriffe probieren ihre Anfragen oft ohnehin bei jedem erreichbaren Server aus. Sie nehmen Angreifern aber eine einfache Vorauswahl und senken die Sichtbarkeit in Suchmaschinen für Server.
Kann ich expose_php im FPM-Pool oder per .htaccess setzen?
Laut PHP-Handbuch ist expose_php nur in der php.ini änderbar. Setzen Sie den Wert deshalb in der php.ini jeder Web-SAPI und starten Sie danach PHP-FPM oder Apache neu.
Warum sehe ich X-Powered-By trotz expose_php = Off?
Dann setzt meist die Anwendung oder ein Framework den Header selbst, oder eine andere php.ini ist aktiv. Entfernen Sie den Header zusätzlich im Webserver: mit fastcgi_hide_header in Nginx oder Header unset in Apache.
Wie prüfe ich meinen Patchstand, wenn die Version nicht mehr sichtbar ist?
Über den Server selbst: Paketverwaltung, Paket-Changelog mit den CVE-Nummern und die Startzeit der PHP-Prozesse. Die Angabe im HTTP-Header war ohnehin kein Nachweis, denn Distributionen spielen Backports oft ohne neue Versionsnummer ein.