Guide de correction

Comment masquer votre version de PHP dans les en-têtes de réponse HTTP

19 avril 2026

Ouvrez l'onglet réseau de votre navigateur sur n'importe quel site basé sur PHP et examinez les en-têtes de réponse du document HTML principal. Sur un grand nombre d'installations, vous trouverez un en-tête ressemblant à X-Powered-By: PHP/8.1.27. C'est PHP qui annonce, très complaisamment, à l'ensemble d'Internet la version qu'il exécute. Il s'agit d'un détail minime que la plupart des propriétaires de sites ne remarquent jamais, mais c'est l'une des informations les plus faciles à collecter pour un attaquant avant de décider si un site mérite d'être sondé plus en profondeur.

Ce guide explique pourquoi cet en-tête existe, ce qu'il révèle réellement, et toutes les façons réalistes de s'en débarrasser. De la configuration du serveur jusqu'au niveau d'un seul site WordPress sur un hébergement mutualisé où vous ne pouvez pas toucher au php.ini.

Ce que l'en-tête révèle réellement à un attaquant

Une valeur telle que PHP/8.1.27 dévoile deux informations utiles. D'abord, la version majeure. Si vous êtes encore sur PHP 7.4 ou PHP 8.0, deux versions arrivées en fin de vie, un attaquant sait immédiatement qu'aucun correctif de sécurité n'arrivera. Ensuite, le numéro exact de correctif. Entre deux versions de correctifs, il existe généralement plusieurs CVE publiquement connues. Un scanner peut comparer la version annoncée à sa base de données CVE et décider en quelques millisecondes s'il continue à insister ou s'il passe à autre chose.

Masquer la version ne corrige évidemment rien. Si votre PHP est obsolète, il reste obsolète. Mais supprimer cette diffusion accomplit trois choses concrètes : cela empêche les scanners automatiques en masse de marquer votre site comme une cible facile, cela rend la reconnaissance manuelle légèrement plus coûteuse, et cela retire une information qui n'a tout simplement rien à faire dans vos en-têtes de réponse. Il n'y a aucune raison légitime pour que l'Internet public connaisse votre niveau de correctif PHP.

Certains référentiels de conformité et listes de contrôle de sécurité (PCI-DSS, BSI IT-Grundschutz, audits internes dans les grandes entreprises) demandent explicitement la suppression de cet en-tête. Même si vous ne travaillez pas dans un tel contexte, il s'agit d'une correction de cinq minutes sans aucun inconvénient.

D'où provient cet en-tête ?

L'en-tête X-Powered-By est émis par PHP lui-même, et non par votre serveur web. Le comportement est contrôlé par une seule directive php.ini appelée expose_php. Lorsque cette directive est définie sur On (ce qui est la valeur par défaut dans la plupart des distributions PHP), PHP ajoute automatiquement l'en-tête à chaque réponse. Désactivez-la et l'en-tête disparaît pour tous les sites de cette installation PHP.

En outre, certains frameworks ou applications ajoutent leurs propres valeurs X-Powered-By. Express, ASP.NET et d'autres le font. WordPress lui-même ne le fait pas, mais des extensions le font occasionnellement. Donc, après avoir désactivé la divulgation de version par PHP, il vaut la peine de revérifier les en-têtes de réponse pour voir si autre chose continue à fuiter.

Option 1 : désactiver expose_php dans php.ini

C'est la correction la plus propre si vous contrôlez le serveur. Ouvrez votre fichier php.ini. Sous Linux, le chemin est généralement l'un des suivants :

  • /etc/php/8.3/fpm/php.ini pour PHP-FPM, la configuration la plus courante derrière nginx et Apache moderne
  • /etc/php/8.3/apache2/php.ini pour Apache avec mod_php
  • /etc/php/8.3/cli/php.ini pour la ligne de commande, qui ne vous intéresse généralement pas dans ce contexte

Le numéro de version dans le chemin correspondra à la version de PHP que vous utilisez. Trouvez la ligne qui indique :

expose_php = On

Modifiez-la en :

expose_php = Off

Enregistrez le fichier et redémarrez le processus PHP pour que la modification prenne effet. Pour PHP-FPM, cela ressemble à :

sudo systemctl restart php8.3-fpm

Pour Apache avec mod_php :

sudo systemctl restart apache2

Pour vérifier, exécutez un curl rapide vers votre site et examinez les en-têtes :

curl -I https://votredomaine.com

La ligne X-Powered-By devrait avoir totalement disparu. Si elle est toujours présente, vous avez modifié le mauvais fichier php.ini (il y en a souvent plusieurs). Vérifiez lequel est réellement chargé avec php --ini en ligne de commande, ou en plaçant un appel phpinfo() temporaire sur le site (et en le supprimant immédiatement après, s'il vous plaît).

Option 2 : définir expose_php par site via .user.ini

Tout le monde n'a pas accès au php.ini global. Sur de nombreux hébergements mutualisés, vous pouvez tout de même influencer les paramètres PHP via un fichier appelé .user.ini, que vous placez à la racine du document de votre site. Créez (ou modifiez) un .user.ini avec :

expose_php = Off

PHP vérifie ce fichier à chaque requête, mais il met en cache le résultat pendant quelques minutes par défaut (contrôlé par user_ini.cache_ttl, généralement 300 secondes). Patientez donc cinq minutes, videz les caches en périphérie, puis revérifiez vos en-têtes.

Une mise en garde : tous les hébergeurs n'autorisent pas la surcharge de expose_php depuis .user.ini. La directive a le mode PHP_INI_PERDIR, ce qui le permet techniquement, mais certains hébergeurs autorisent explicitement uniquement certains paramètres. Si le réglage n'a aucun effet après quelques minutes, votre hébergeur le bloque probablement. Passez à l'Option 5.

Option 3 : supprimer l'en-tête dans Apache

Vous pouvez également retirer l'en-tête au niveau du serveur web, ce qui fonctionne quel que soit le comportement interne de PHP. Dans votre configuration Apache (ou dans le .htaccess du site, si AllowOverride le permet), ajoutez :

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

La raison d'utiliser à la fois unset et always unset est que la version standard ne s'applique qu'aux réponses 2xx réussies. La variante always s'applique également aux réponses d'erreur comme les pages 500, où vous ne voulez précisément pas que la version fuite non plus.

mod_headers doit être activé pour que cela fonctionne. Sur Debian et Ubuntu :

sudo a2enmod headers
sudo systemctl reload apache2

Si vous êtes sur un hébergement mutualisé avec Apache, la variante .htaccess fonctionne presque toujours, car la plupart des hébergeurs activent mod_headers et l'autorisent via AllowOverride All. Si la règle n'a aucun effet, demandez à votre hébergeur si mod_headers est disponible.

Option 4 : supprimer l'en-tête dans nginx

Sur nginx, l'équivalent va dans le bloc server de votre site, ou dans un bloc http général si vous le souhaitez à l'échelle du site :

more_clear_headers 'X-Powered-By';

Petit piège : more_clear_headers nécessite le module headers-more-nginx-module, qui ne fait pas partie du paquet nginx standard sur toutes les distributions. Debian et Ubuntu le fournissent dans le paquet nginx-extras :

sudo apt install nginx-extras

Si vous êtes coincé sur du nginx ordinaire sans le module extras, il existe un contournement utilisant fastcgi_hide_header. C'est en réalité le bon outil si l'en-tête provient de PHP-FPM (ce qui est le cas la plupart du temps) :

location ~ \.php$ {
    # vos directives habituelles fastcgi_pass et params
    fastcgi_hide_header X-Powered-By;
}

Rechargez nginx avec sudo nginx -t && sudo systemctl reload nginx et vérifiez avec curl -I.

Option 5 : cas particulier, WordPress

WordPress lui-même ne définit pas X-Powered-By. L'en-tête provient de PHP. Donc tout ce qui précède s'applique sans changement : désactiver expose_php ou retirer l'en-tête dans Apache ou nginx résoudra également le problème pour un site WordPress. Mais WordPress vous offre deux angles supplémentaires qu'il vaut la peine de connaître.

Supprimer l'en-tête depuis l'intérieur de WordPress. Si vous n'avez pas accès à la configuration du serveur web et que .user.ini ne fonctionne pas chez votre hébergeur, vous pouvez retirer l'en-tête de manière programmatique via une must-use extension. Créez un fichier à wp-content/mu-plugins/remove-powered-by.php (créez le dossier mu-plugins s'il n'existe pas encore) et placez-y ceci :

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

Deux points à garder à l'esprit avec cette approche. Premièrement, header_remove() ne fonctionne que si PHP n'a pas encore commencé à envoyer le corps de la réponse. Le hook send_headers se déclenche au bon moment pour chaque page WordPress normale, donc cela fonctionne pour les articles, les pages, l'administration et l'API REST. Cela n'aide pas pour les requêtes qui n'atteignent jamais WordPress, comme les appels directs à des fichiers statiques ou les pages mises en cache servies par un proxy inverse. Deuxièmement, certains hébergeurs exécutent un proxy inverse (Cloudflare, Varnish, Nginx devant Apache) qui lit l'en-tête de la réponse du backend et le transmet tel quel. Si l'en-tête apparaît toujours dans votre navigateur après avoir installé cette extension, le proxy le met en cache. Videz le cache et, idéalement, retirez l'en-tête au niveau du proxy également.

WordPress expose également sa propre version. Tant que vous y êtes, vous voudrez probablement traiter la balise <meta name="generator" content="WordPress X.Y.Z"> que WordPress place dans l'en-tête HTML, ainsi que les paramètres ?ver=X.Y.Z sur les fichiers CSS et JS. Ce n'est pas la même chose que l'en-tête de version PHP, mais cela divulgue la version exacte de WordPress, ce qui est tout aussi utile pour un attaquant. L'extrait ci-dessous gère les deux :

<?php
// Supprime la balise meta generator
remove_action('wp_head', 'wp_generator');

// Retire la version WordPress des flux RSS, de l'admin, etc.
add_filter('the_generator', '__return_empty_string');

// Supprime ?ver=X.Y.Z des URL des fichiers CSS et JS
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);

Notez que retirer le paramètre ?ver= a un effet secondaire : le navigateur ne peut plus déterminer si un fichier CSS ou JS a changé sur la seule base de l'URL. Si vous comptez sur cela pour le cache busting, soit laissez le filtre de côté, soit remplacez ver par un hachage du contenu du fichier.

Option 6 : Cloudflare, Sucuri et autres proxys inverses

Si vous êtes derrière Cloudflare ou un CDN similaire, vous pouvez retirer l'en-tête une couche plus loin, ce qui est pratique car cela couvre tous les sites que vous routez via la même zone sans toucher à l'origine. Dans Cloudflare, cela se fait via une Transform Rule de type « Modify Response Header » :

  • Nom de la règle : « Remove X-Powered-By »
  • Quand les requêtes entrantes correspondent : Hostname equals votredomaine.com (ou un caractère générique si vous voulez une portée à l'échelle de la zone)
  • Alors : Remove header X-Powered-By

Sucuri, BunnyCDN, Fastly et la plupart des autres proxys inverses proposent un équivalent. La formulation exacte dans le tableau de bord varie, mais la fonctionnalité que vous recherchez s'appelle toujours « modify response headers » ou « edge rules ».

Autres en-têtes à vérifier tant que vous y êtes

PHP n'est pas la seule chose à être bavarde sur elle-même dans les en-têtes de réponse. Tant que vous avez curl ouvert, scannez les en-têtes à la recherche de l'un des éléments suivants :

  • Server: Apache/2.4.58 (Ubuntu) dévoile la version de correctif d'Apache et la variante de votre OS. Supprimez via ServerTokens Prod et ServerSignature Off dans Apache, ou server_tokens off dans nginx.
  • X-Powered-CMS, X-Generator, X-Drupal-Cache ou similaires. Habituellement définis par des extensions ou des modules spécifiques au CMS. Supprimez de la même manière que X-Powered-By.
  • X-AspNet-Version ou X-AspNetMvc-Version. Pertinent uniquement si quelque chose dans votre stack touche à .NET, mais bon à savoir.

InspectWP signale tous ces éléments dans la section des en-têtes de sécurité de votre rapport. Une fois la version de PHP masquée, lancer une nouvelle analyse est le moyen le plus rapide de voir quelles autres petites indiscrétions sont encore sur le fil.

Vérifier et c'est terminé

Quelle que soit la voie choisie, effectuez une dernière vérification :

  1. Ouvrez un terminal et exécutez curl -I https://votredomaine.com.
  2. Parcourez la sortie. Il ne devrait plus y avoir aucune ligne X-Powered-By.
  3. Répétez pour une URL d'administration (pour WordPress, essayez wp-login.php) et pour une page d'erreur (ajoutez une chaîne aléatoire à l'URL pour déclencher un 404). L'en-tête doit rester absent partout.
  4. Si vous utilisez Cloudflare ou un cache, testez également depuis une nouvelle IP ou avec un contournement de cache, afin d'être sûr de regarder une réponse en direct et non une réponse mise en cache.
  5. Lancez une nouvelle analyse InspectWP. La vérification de la version de PHP dans la section Hébergement se rabattra désormais sur d'autres méthodes de détection ou marquera la version comme non divulguée, ce qui est ce que vous recherchez.

Masquer la version de PHP ne remplace pas le maintien à jour de PHP. C'est une petite étape dans un tableau de durcissement plus large. Mais c'est le genre de gain rapide qui prend cinq minutes, supprime une information gratuite que les attaquants collectent autrement pour rien, et ne vous coûte exactement rien en retour.

Vérifiez votre site WordPress dès maintenant

InspectWP analyse votre site WordPress pour détecter les problèmes de sécurité, de SEO, de conformité RGPD et de performance — gratuitement.

Analyser votre site gratuitement