Poradnik naprawy

Jak ukryć wersję PHP w nagłówkach odpowiedzi HTTP

19 kwietnia 2026

Otwórz zakładkę network swojej przeglądarki na dowolnej stronie opartej na PHP i obejrzyj nagłówki odpowiedzi dla głównego dokumentu HTML. W wielu instalacjach znajdziesz nagłówek wyglądający mniej więcej tak: X-Powered-By: PHP/8.1.27. To PHP usłużnie mówi całemu internetowi, jaka wersja działa. To mały szczegół, którego większość właścicieli witryn nigdy nie zauważa, ale okazuje się być jedną z łatwiejszych informacji, które atakujący zbiera, zanim zdecyduje, czy witryna jest warta dalszego badania.

Ten przewodnik wyjaśnia, dlaczego nagłówek w ogóle istnieje, co faktycznie ujawnia i każdy realistyczny sposób na pozbycie się go. Od konfiguracji serwera po poziom pojedynczej witryny WordPress na shared hostingu, gdzie nie możesz dotknąć php.ini.

Co nagłówek naprawdę mówi atakującemu

Wartość taka jak PHP/8.1.27 ujawnia dwa użyteczne fakty. Po pierwsze, wersję główną. Jeśli jesteś nadal na PHP 7.4 lub PHP 8.0, które oba osiągnęły koniec życia, atakujący od razu wie, że nie będzie więcej łatek bezpieczeństwa. Po drugie, dokładny poziom łatki. Między dwoma wydaniami łatek jest zwykle garść publicznie znanych CVE. Skaner może porównać Twoją zgłoszoną wersję ze swoją bazą CVE i w milisekundach zdecydować, czy nadal sondować, czy iść dalej.

Ukrycie wersji oczywiście niczego nie łata. Jeśli Twój PHP jest przestarzały, nadal jest przestarzały. Ale usunięcie transmisji robi trzy konkretne rzeczy: powstrzymuje automatyczne skanery masowe przed oznaczeniem Twojej witryny jako tani cel, czyni ręczny rekonesans nieco droższym i usuwa fragment informacji, który po prostu nie ma czego szukać w Twoich nagłówkach odpowiedzi. Nie ma żadnego uzasadnionego powodu, dla którego publiczny internet powinien znać poziom łatki Twojego PHP.

Niektóre ramy zgodności i checklisty bezpieczeństwa (PCI-DSS, BSI IT-Grundschutz, wewnętrzne audyty w większych firmach) wyraźnie wymagają wyłączenia tego nagłówka. Nawet jeśli nie pracujesz w jednym z tych kontekstów, to pięciominutowa poprawka bez wad.

Skąd pochodzi nagłówek?

Nagłówek X-Powered-By jest wysyłany przez samo PHP, nie przez Twój webserwer. Zachowanie jest kontrolowane przez pojedynczą dyrektywę php.ini o nazwie expose_php. Gdy ta dyrektywa jest ustawiona na On (co jest domyślne w większości dystrybucji PHP), PHP automatycznie dodaje nagłówek do każdej odpowiedzi. Wyłącz to, a nagłówek znika dla każdej witryny na tej instalacji PHP.

Ponadto niektóre frameworki lub aplikacje dodają własne wartości X-Powered-By. Express, ASP.NET i inne robią to. Sam WordPress tego nie robi, ale wtyczki czasami tak. Więc po wyłączeniu wzmianki o wersji PHP, warto ponownie sprawdzić nagłówki odpowiedzi, aby zobaczyć, czy coś jeszcze wycieka.

Opcja 1: Wyłącz expose_php w php.ini

To najczystsze rozwiązanie, jeśli zarządzasz serwerem. Otwórz plik php.ini. Na Linuksie ścieżka to zwykle jedna z tych:

  • /etc/php/8.3/fpm/php.ini dla PHP-FPM, najczęstszej konfiguracji za nginx i nowoczesnym Apache
  • /etc/php/8.3/apache2/php.ini dla Apache z mod_php
  • /etc/php/8.3/cli/php.ini dla wiersza poleceń, gdzie zwykle Cię to nie obchodzi w tym kontekście

Numer wersji w ścieżce odpowiada używanej wersji PHP. Znajdź linię, która brzmi:

expose_php = On

Zmień to na:

expose_php = Off

Zapisz plik i zrestartuj proces PHP, aby zmiana zaczęła obowiązywać. Dla PHP-FPM wygląda to tak:

sudo systemctl restart php8.3-fpm

Dla Apache z mod_php:

sudo systemctl restart apache2

Aby zweryfikować, wykonaj szybki curl przeciwko swojej witrynie i obejrzyj nagłówki:

curl -I https://twojadomena.com

Linia X-Powered-By powinna całkowicie zniknąć. Jeśli nadal tam jest, edytowałeś niewłaściwy plik php.ini (często jest więcej niż jeden). Sprawdź, który jest faktycznie ładowany za pomocą php --ini w wierszu poleceń, lub tymczasowo umieszczając wywołanie phpinfo() na witrynie (i usuwając je zaraz potem, proszę).

Opcja 2: Ustaw expose_php per witryna przez .user.ini

Nie każdy ma dostęp do globalnego php.ini. Na wielu shared hostach możesz nadal wpływać na ustawienia PHP przez plik o nazwie .user.ini, który umieszczasz w document root swojej witryny. Utwórz (lub edytuj) .user.ini z:

expose_php = Off

PHP sprawdza ten plik przy każdym żądaniu, ale domyślnie cache'uje wynik przez kilka minut (kontrolowany przez user_ini.cache_ttl, zwykle 300 sekund). Daj mu więc pięć minut, wyczyść wszelkie cache na brzegu, a następnie sprawdź swoje nagłówki ponownie.

Uwaga ostrzegawcza: nie wszystkie hosty pozwalają na nadpisanie expose_php z .user.ini. Dyrektywa ma tryb PHP_INI_PERDIR, który technicznie to umożliwia, ale niektóre hosty wyraźnie umieszczają na białej liście to, co można zmienić. Jeśli ustawienie nie ma efektu po kilku minutach, Twój host prawdopodobnie to blokuje. Przejdź do Opcji 5.

Opcja 3: Usuń nagłówek w Apache

Możesz również usunąć nagłówek na poziomie webserwera, co działa niezależnie od tego, co PHP robi wewnętrznie. Dodaj w konfiguracji Apache (lub w .htaccess witryny, jeśli AllowOverride na to pozwala):

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

Powodem użycia zarówno unset, jak i always unset jest to, że zwykła wersja stosuje się tylko do udanych odpowiedzi 2xx. Wariant always ma zastosowanie również do odpowiedzi błędów, takich jak strony 500, co jest dokładnie miejscem, gdzie również nie chcesz, aby wersja wyciekała.

mod_headers musi być włączony, aby to działało. Na Debianie i Ubuntu:

sudo a2enmod headers
sudo systemctl reload apache2

Jeśli jesteś na shared hostingu z Apache, wariant .htaccess prawie zawsze działa, ponieważ większość hosterów włącza mod_headers i zezwala na to przez AllowOverride All. Jeśli reguła nie ma efektu, zapytaj swojego hosta, czy mod_headers jest dostępny.

Opcja 4: Usuń nagłówek w nginx

Na nginx ekwiwalent idzie w bloku server Twojej witryny, lub w ogólnym bloku http, jeśli chcesz tego site-wide:

more_clear_headers 'X-Powered-By';

Małe zastrzeżenie: more_clear_headers wymaga headers-more-nginx-module, który nie jest częścią standardowego pakietu nginx w każdej dystrybucji. Debian i Ubuntu dostarczają go w pakiecie nginx-extras:

sudo apt install nginx-extras

Jeśli utknąłeś na gołym nginx bez modułu extras, jest obejście z fastcgi_hide_header. To jest właściwie odpowiednie narzędzie, jeśli nagłówek pochodzi z PHP-FPM (co jest tak w większości przypadków):

location ~ \.php$ {
    # your usual fastcgi_pass and params
    fastcgi_hide_header X-Powered-By;
}

Przeładuj nginx za pomocą sudo nginx -t && sudo systemctl reload nginx i zweryfikuj za pomocą curl -I.

Opcja 5: Przypadek specjalny, WordPress

Sam WordPress nie ustawia X-Powered-By. Nagłówek pochodzi z PHP. Więc wszystko powyższe ma zastosowanie bez zmian: wyłączenie expose_php lub usunięcie nagłówka w Apache lub nginx rozwiązuje to również dla witryny WordPress. Ale WordPress daje Ci dwa dodatkowe kąty warte poznania.

Wyłącz nagłówek z WordPress. Jeśli nie masz dostępu do konfiguracji webserwera, a .user.ini nie działa na Twoim hoście, możesz programowo usunąć nagłówek przez wtyczkę must-use. Utwórz plik w wp-content/mu-plugins/remove-powered-by.php (utwórz folder mu-plugins, jeśli jeszcze nie istnieje) i umieść to tam:

<?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');
    }
});

Dwie rzeczy, których należy być świadomym z tym podejściem. Po pierwsze, header_remove() działa tylko, jeśli PHP nie zaczął jeszcze wysyłać body odpowiedzi. Hook send_headers jest wyzwalany w odpowiednim momencie dla każdej normalnej strony WordPress, więc to działa dla wpisów, stron, admina i REST API. Nie pomaga dla żądań, które nigdy nie docierają do WordPress, takich jak bezpośrednie wywołania plików statycznych lub stron z cache serwowanych przez reverse proxy. Po drugie, niektóre hosty uruchamiają reverse proxy (Cloudflare, Varnish, Nginx przed Apache), który czyta nagłówek z odpowiedzi backendu i przekazuje go niezmienionego. Jeśli nagłówek nadal pojawia się w Twojej przeglądarce po zainstalowaniu tej wtyczki, proxy go cache'uje. Wyczyść cache i, najlepiej, usuń nagłówek również na poziomie proxy.

WordPress również ujawnia własną wersję. Skoro już tym się zajmujesz, prawdopodobnie chcesz również poradzić sobie z tagiem <meta name="generator" content="WordPress X.Y.Z">, który WordPress umieszcza w head HTML, oraz parametrami ?ver=X.Y.Z na plikach CSS i JS. Te nie są tym samym co nagłówek wersji PHP, ale wyciekają dokładną wersję WordPress, co jest podobnie użyteczne dla atakującego. Poniższy fragment obejmuje oba:

<?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);

Zauważ, że usunięcie parametru ?ver= ma efekt uboczny: przeglądarka nie może już określić wyłącznie na podstawie URL, kiedy plik CSS lub JS został zmieniony. Jeśli polegasz na tym dla cache-busting, pomiń filtr lub zastąp ver hashem zawartości pliku.

Opcja 6: Cloudflare, Sucuri i inne reverse proxy

Jeśli jesteś za Cloudflare lub podobnym CDN, możesz usunąć nagłówek jeszcze o warstwę dalej, co jest miłe, ponieważ obejmuje każdą witrynę kierowaną przez tę samą strefę bez dotykania origin. W Cloudflare odbywa się to przez Transform Rule typu "Modify Response Header":

  • Nazwa reguły: "Remove X-Powered-By"
  • Gdy przychodzące żądania pasują: Hostname equals twojadomena.com (lub wildcard, jeśli chcesz zone-wide)
  • Wtedy: Usuń nagłówek X-Powered-By

Sucuri, BunnyCDN, Fastly i większość innych reverse proxy oferuje ekwiwalent. Dokładne sformułowanie w panelu różni się, ale funkcja, której szukasz, to zawsze "modify response headers" lub "edge rules".

Inne nagłówki warte sprawdzenia przy okazji

PHP nie jest jedynym, który ma tendencję do bycia głośnym o sobie w nagłówkach odpowiedzi. Gdy masz curl otwarty, przeskanuj nagłówki pod kątem któregokolwiek z następujących:

  • Server: Apache/2.4.58 (Ubuntu) ujawnia wersję patcha Apache i smak Twojego OS. Wyłącz przez ServerTokens Prod i ServerSignature Off w Apache, lub server_tokens off w nginx.
  • X-Powered-CMS, X-Generator, X-Drupal-Cache lub podobne. Zwykle ustawiane przez wtyczki lub moduły specyficzne dla CMS. Usuń w ten sam sposób co X-Powered-By.
  • X-AspNet-Version lub X-AspNetMvc-Version. Istotne tylko, jeśli coś w Twoim stosie dotyka .NET, ale warto wiedzieć.

InspectWP oznacza je wszystkie w sekcji nagłówków bezpieczeństwa raportu. Po ukryciu wersji PHP, uruchomienie nowego skanu jest najszybszym sposobem zobaczenia, jakie inne małe zdrady są jeszcze na linii.

Zweryfikuj i jesteś gotowy

Po której drodze poszedłeś, wykonaj jedną ostatnią kontrolę:

  1. Otwórz terminal i wykonaj curl -I https://twojadomena.com.
  2. Spójrz na wyjście. Nie powinno być w ogóle linii X-Powered-By.
  3. Powtórz dla URL admina (spróbuj wp-login.php dla WordPress) i dla strony błędu (dodaj losowy ciąg do URL, aby wyzwolić 404). Nagłówek powinien pozostać zniknięty wszędzie.
  4. Jeśli używasz Cloudflare lub cache, testuj również ze świeżego IP lub z cache-bypass, abyś wiedział, że patrzysz na żywą odpowiedź, a nie zbuforowaną.
  5. Uruchom nowy skan InspectWP. Kontrola wersji PHP w sekcji Hosting wróci teraz do innych metod detekcji lub oznaczy wersję jako nieujawnioną, co jest tym, czego chcesz.

Ukrycie wersji PHP nie jest zamiennikiem utrzymywania PHP na bieżąco. To jeden mały krok w większym obrazie hardeningu. Ale to rodzaj szybkiej wygranej, która zajmuje pięć minut, usuwa jeden darmowy kawałek informacji, który atakujący w przeciwnym razie zbierze za darmo, i kosztuje Cię dokładnie zero w zamian.

Sprawdź teraz swoją stronę WordPress

InspectWP analizuje Twoją stronę WordPress pod kątem bezpieczeństwa, problemów SEO, zgodności z RODO i wydajności — za darmo.

Przeanalizuj stronę za darmo