Aktualna sytuacja: PHP2Shell. Dwie krytyczne luki w PHP (CVSS 9,2) umożliwiają wykonanie złośliwego kodu bez logowania. Poprawki od 21.10.2026.Co należy teraz zrobić →

expose_php i nagłówki Server: ukrywanie informacji o wersji

PHP, Nginx i Apache domyślnie podają numer wersji w każdej odpowiedzi. Nie chroni to przed atakami, ale daje skanerom wygodną listę celów. Jak to wyłączyć i mimo to zachować przegląd.

Stan 5 min czytaniaUtwardzanie i konfiguracja

Krótko: Dzięki expose_php = Off w php.ini znika nagłówek X-Powered-By: PHP/…. Do tego należą server_tokens off; w Nginx oraz ServerTokens Prod i ServerSignature Off w Apache. Nie czyni to żadnego serwera bezpieczniejszym, ale odbiera zautomatyzowanym skanom gotową listę wersji. Własny stan poprawek sprawdzają Państwo potem przez menedżer pakietów i procesy, a nie przez nagłówki.

Wizytówka w każdej odpowiedzi

Kto po 21 października 2026 chciał wiedzieć, ile serwerów nadal pokazuje starą wersję PHP, nie musiał długo szukać. Wiele serwerów WWW podaje wersję PHP w każdej pojedynczej odpowiedzi, na przykład jako X-Powered-By: PHP/8.2.20. Ogólnoświatowe usługi wyszukiwania odczytują te informacje, a Unit 42 z Palo Alto Networks naliczył dla PHP2Shell ponad 22,6 mln wystawionych, potencjalnie podatnych instancji.

Dla atakujących taka informacja to skrót. Mogą wstępnie sortować cele, zamiast próbować na ślepo. Dla operatorów jest natomiast bezużyteczna, bo nie dowodzi nawet własnego stanu poprawek: dystrybucje często dostarczają poprawki jako backport bez nowego numeru wersji.

Ten artykuł pokazuje, gdzie PHP i serwer WWW ujawniają informacje o wersji i jak je wyłączyć. Mówi też otwarcie, co to daje, a czego nie.

Gdzie wszędzie pojawiają się informacje o wersji

Wersja PHP to tylko jedno z kilku miejsc. Warto spojrzeć na całość, bo jedno zapomniane miejsce niweczy pozostałe środki.

Miejsce Przykład Wyłączanie przez
Nagłówek HTTP z PHP X-Powered-By: PHP/8.3.x expose_php = Off w php.ini
Nagłówek HTTP serwera WWW Server: nginx/1.x lub Server: Apache/2.4.x (Debian) server_tokens off; lub ServerTokens Prod
Strony błędów serwera WWW wiersz z wersją pod stronami 404 lub 500 te same ustawienia, w Apache dodatkowo ServerSignature Off
Nagłówki aplikacji własne informacje X-Powered-By frameworków fastcgi_hide_header lub Header unset
Pliki w katalogu głównym pliki testowe phpinfo(), pliki Readme i Changelog usunąć lub zablokować
Komunikaty błędów PHP ścieżki i szczegóły wersji w przeglądarce display_errors = Off

Pliki testowe z phpinfo() są dla atakujących najbogatszym źródłem. Zdradzają nie tylko wersję, ale całą konfigurację; więcej w artykule Pliki phpinfo(): dlaczego muszą zniknąć.

Wyłączanie expose_php w php.ini

Według podręcznika PHP expose_php jest domyślnie włączone i można je zmieniać tylko w php.ini, nie w puli, nie przez .htaccess i nie w czasie działania. Proszę więc ustawić wartość w php.ini każdego trybu pracy, który obsługuje strony, czyli w Debianie i Ubuntu na przykład w /etc/php/<version>/fpm/ oraz ewentualnie w /etc/php/<version>/apache2/.

; php.ini SAPI WWW, potem zrestartować PHP-FPM lub Apache
expose_php = Off

Jeśli równolegle działa kilka wersji PHP, każda wymaga własnego wpisu. Restart danej usługi jest obowiązkowy, ponieważ PHP odczytuje php.ini tylko przy starcie.

Skracanie nagłówków Server w Nginx i Apache

Nginx domyślnie podaje swoją wersję w nagłówku Server i na stronach błędów. Z server_tokens off; pozostaje tylko nazwa produktu. Dodatkowo nagłówek X-Powered-By, który ustawia sama aplikacja, można odfiltrować za pomocą fastcgi_hide_header. Według dokumentacji Nginx sam z siebie ukrywa tylko Status i X-Accel-…, a nie X-Powered-By.

# w bloku http, obowiązuje dla wszystkich stron
server_tokens off;
fastcgi_hide_header X-Powered-By;

W Apache ServerTokens steruje nagłówkiem Server i jednocześnie wierszem wersji pod stronami błędów. Według dokumentacji Apache ustawienie obowiązuje tylko dla całego serwera, a nie dla pojedynczego VirtualHost. Ponieważ odpowiedzi PHP-FPM przez mod_proxy_fcgi trafiają do innej tabeli nagłówków niż odpowiedzi samego serwera, proszę zastosować usuwanie w obu wariantach.

# konfiguracja dla całego serwera, np. /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off

# wymaga mod_headers
<IfModule mod_headers.c>
    Header unset X-Powered-By
    Header always unset X-Powered-By
</IfModule>

Przed przeładowaniem proszę sprawdzić konfigurację za pomocą nginx -t lub apachectl configtest. Jak za pomocą nagłówków aktywnie włączyć ochronę odwiedzających, na przykład HSTS lub Content-Security-Policy, opisuje poradnik Nagłówki bezpieczeństwa dla stron WWW.

Jak sprawdzić wynik z zewnątrz

Po przestawieniu proszę sprawdzić każdą domenę osobno, najlepiej także stronę błędu. Poniższe polecenia wysyłają tylko zwykłe żądania do Państwa własnych stron:

# Nagłówki strony głównej
curl -sI https://www.example.de/ | grep -iE '^(server|x-powered-by):'
# Nagłówki nieistniejącej strony
curl -sI https://www.example.de/gibt-es-nicht-4711 | grep -iE '^(server|x-powered-by):'

Oczekiwany jest nagłówek Server bez numeru wersji i brak X-Powered-By. Jeśli nadal widnieje tam wersja PHP, zwykle aktywny jest inny php.ini albo jakaś usługa nie została jeszcze zrestartowana. Jeśli przed serwerem stoi CDN, proszę dodatkowo sprawdzić bezpośrednio serwer źródłowy, o ile jest osiągalny.

Wskazówka

Proszę mimo to zachować wersję PHP wewnętrznie: w inwentarzu serwerów, ze stanem pakietów i datą ostatniej kontroli. Stan poprawek dowodzi się na serwerze, jak opisano w artykule Prawidłowe sprawdzanie wersji PHP i stanu poprawek.

Co daje ukrywanie, a czego nie

Uczciwie oceniając, wyłączenie informacji o wersji to mały środek o niewielkim nakładzie pracy. Zmniejsza prawdopodobieństwo pojawienia się w celowych wyszukiwaniach określonych wersji i ogranicza informacje, które atakujący otrzymuje bez wysiłku.

Nie chroni jednak przed zautomatyzowanymi atakami, które po prostu wysyłają żądania do każdego osiągalnego serwera. Jak przebiegają takie masowe skany, opisuje artykuł Masowe skany w poszukiwaniu niezałatanego PHP. Wobec PHP2Shell pomaga tylko aktualizacja do PHP 8.5.12, 8.4.27, 8.3.36 lub 8.2.35 albo potwierdzonego backportu, a następnie restart wszystkich procesów PHP.

Efekt uboczny jest natomiast wyjątkowo użyteczny: kto wyłącza informacje o wersji na zewnątrz, musi rzetelnie ewidencjonować wersje wewnętrznie. W sytuacji takiej jak PHP2Shell właśnie ten przegląd decyduje o tym, jak szybko wiedzą Państwo, które serwery są dotknięte.

Ukrywanie ma więc sens jako element podstawowego utwardzania, a nie jako pojedynczy środek. Należy do tej samej listy kontrolnej co wyłączone wyświetlanie błędów, usunięte pliki testowe i zablokowane wartości konfiguracji.

Jak konkretnie pomaga PHP SOS?

  • Inwentaryzacja miejsc: sprawdzamy nagłówki, strony błędów i katalog główny wszystkich domen pod kątem informacji o wersji i zapomnianych plików testowych.
  • Dostosowanie konfiguracji: ustawiamy expose_php, nagłówki Server i filtry nagłówków w każdej wersji PHP i każdym serwerze WWW oraz kontrolowanie restartujemy usługi.
  • Wewnętrzne udokumentowanie stanu poprawek: dokumentujemy wersje i stany pakietów tam, gdzie ich miejsce, w inwentarzu, a nie w nagłówku HTTP.
  • Włączenie w utwardzanie: środek jest częścią naszego utwardzania serwerów dla serwerów WWW z PHP.

Częste pytania

Czy expose_php = Off sprawia, że mój serwer jest bezpieczny?

Nie. To ustawienie usuwa tylko informację o wersji z nagłówka HTTP. Podatna wersja PHP pozostaje podatna, a zautomatyzowane ataki i tak często wysyłają swoje żądania do każdego osiągalnego serwera. Odbiera jednak atakującym łatwą wstępną selekcję i zmniejsza widoczność w wyszukiwarkach serwerów.

Czy mogę ustawić expose_php w puli FPM lub przez .htaccess?

Według podręcznika PHP expose_php można zmieniać tylko w php.ini. Proszę więc ustawić wartość w php.ini każdego SAPI WWW, a następnie zrestartować PHP-FPM lub Apache.

Dlaczego widzę X-Powered-By mimo expose_php = Off?

Wtedy nagłówek ustawia zwykle sama aplikacja lub framework albo aktywny jest inny plik php.ini. Nagłówek należy dodatkowo usunąć w serwerze WWW: za pomocą fastcgi_hide_header w Nginx lub Header unset w Apache.

Jak sprawdzić stan poprawek, jeśli wersja nie jest już widoczna?

Na samym serwerze: menedżer pakietów, changelog pakietu z numerami CVE i czas uruchomienia procesów PHP. Informacja w nagłówku HTTP i tak nie była dowodem, ponieważ dystrybucje często wgrywają backporty bez nowego numeru wersji.

Źródła

Kontakt natychmiast

Liczy się każda godzina. Proszę napisać do nas teraz.

Proszę krótko opisać system, wersję PHP i obserwacje. Skontaktujemy się z Państwem, ustalimy sytuację i będziemy pracować zdalnie, aż incydent zostanie zamknięty i udokumentowany.

Natychmiastowa pomoc