# Filtrer les en-têtes HTTP sortants pour ne pas trop en dire à un attaquant

> Version de PHP, nom du serveur, technologie utilisée : les en-têtes de réponse en révèlent souvent plus qu'il ne faudrait. Checklist pour les filtrer au niveau du serveur web.

- Auteur : Clément Hadrot
- Publié le : 2024-04-11
- Mis à jour le : 2024-04-11
- Catégorie : Sécurité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/securite/filtrer-en-tetes-http-sortants-wordpress/

## L’essentiel

- X-Powered-By expose la version de PHP par défaut
- Le filtrage se fait mieux au niveau du serveur web qu'en PHP
- Un en-tête verbeux facilite le ciblage d'une faille connue

Un audit de reconnaissance externe commence presque toujours par la même commande, anodine en apparence : `curl -I https://exemple.fr`. Cette simple requête, qui ne récupère que les en-têtes de la réponse sans télécharger la page, en dit souvent davantage sur l'infrastructure d'un site que des heures de scan actif. Sur nombre de sites WordPress encore aujourd'hui, cette commande révèle la version exacte de PHP, le logiciel serveur utilisé et parfois même le système d'exploitation sous-jacent, toutes ces informations étant transmises sans qu'aucune configuration explicite ne l'ait demandé.

Cette checklist se concentre sur les en-têtes de réponse eux-mêmes, ceux que le serveur envoie au navigateur, à ne pas confondre avec les en-têtes de sécurité applicative comme la *Content Security Policy* ou HSTS, qui répondent à un objectif différent et ont déjà fait l'objet d'un article dédié sur ce blog. Il s'agit ici de réduire ce qu'un attaquant peut apprendre passivement, avant même de tenter la moindre action offensive.

## Ce que révèlent les en-têtes par défaut

Sur une installation WordPress standard, hébergée sur une pile Apache ou Nginx classique, une requête `curl -I` renvoie fréquemment ces informations :

| En-tête | Ce qu'il révèle |
| --- | --- |
| `X-Powered-By` | Version exacte de PHP, par exemple `PHP/8.1.27` |
| `Server` | Logiciel serveur et parfois sa version, par exemple `Apache/2.4.57 (Debian)` |
| `X-Generator` | Confirmation explicite de l'usage de WordPress, ajoutée par certains thèmes ou extensions |

Aucune de ces informations n'est indispensable au fonctionnement du site. Elles servent uniquement, pour un attaquant en phase de reconnaissance, à cibler plus vite les vulnérabilités connues correspondant précisément à cette version de PHP ou de serveur, plutôt que de tester à l'aveugle une liste de failles génériques.

## Filtrer côté serveur web plutôt qu'en PHP

> L'essentiel à retenir : X-Powered-By expose la version de PHP par défaut ; Le filtrage se fait mieux au niveau du serveur web qu'en PHP ; Un en-tête verbeux facilite le ciblage d'une faille connue

Il est possible de masquer `X-Powered-By` en PHP avec `header_remove('X-Powered-By')`, mais cette approche présente un défaut : elle s'exécute après que PHP ait déjà décidé d'ajouter l'en-tête, et certaines configurations (erreurs précoces, pages générées hors du cycle normal de WordPress) peuvent laisser passer l'en-tête malgré tout. La bonne pratique consiste à désactiver l'ajout à la source, dans la configuration de PHP elle-même, via `php.ini` ou une directive équivalente :

```
# Dans php.ini ou un fichier .user.ini
expose_php = Off
```

Sur Nginx, le nom et la version du serveur s'effacent avec une directive globale, à placer dans le bloc `http` de la configuration principale :

```
http {
    server_tokens off;
}
```

Sur Apache, deux directives combinées suffisent, généralement placées dans `httpd.conf` ou un fichier de configuration global (elles n'ont pas d'effet dans un `.htaccess`) :

```
ServerTokens Prod
ServerSignature Off
```

`ServerTokens Prod` réduit l'en-tête `Server` à la seule mention `Apache`, sans numéro de version ni système d'exploitation. `ServerSignature Off` supprime la ligne de signature qu'Apache ajoute par défaut au bas des pages d'erreur générées par le serveur lui-même (404, 500), qui révèle souvent les mêmes informations dans le corps de la réponse plutôt que dans un en-tête.

## Le cas particulier des pages d'erreur et des sous-domaines de développement

Les pages d'erreur générées directement par le serveur web, avant même que WordPress n'intervienne, méritent une vérification séparée : une erreur 500 mal configurée peut afficher un chemin de fichier complet du serveur, une trace d'exécution PHP, ou une bannière de version. Sur un environnement de développement accessible via un sous-domaine de type `*.dev.exemple.fr`, ce risque est souvent plus élevé parce que `WP_DEBUG_DISPLAY` y reste activé plus longtemps qu'en production.

- Vérifier que `display_errors` est désactivé en production, même sur les sous-domaines de recette accessibles publiquement.
- Personnaliser les pages d'erreur 404 et 500 pour qu'elles ne renvoient qu'un message générique, sans détail technique.
- Confirmer, avec `curl -I`, qu'aucun en-tête `X-Powered-By` ni `Server` verbeux ne subsiste après modification, y compris derrière un CDN ou un reverse proxy qui pourrait réintroduire ses propres en-têtes.

## Vérifier après un changement d'infrastructure

Ce filtrage se perd facilement lors d'une migration d'hébergeur, d'un changement de version de PHP géré par un panneau de contrôle, ou de l'ajout d'un CDN qui réécrit certains en-têtes à son tour. Il est utile d'intégrer une vérification simple dans le processus de mise en production :

```
curl -sI https://exemple.fr | grep -Ei 'x-powered-by|^server:|x-generator'
```

Une commande qui ne renvoie rien confirme que le filtrage est effectif. Sur un parc de plusieurs sites, ce contrôle se scripte facilement en boucle sur une liste de domaines, pour détecter d'un coup d'œil les serveurs qui auraient régressé après une mise à jour système.

> Masquer un en-tête ne corrige aucune faille, mais retire à l'attaquant une information gratuite qui lui aurait fait gagner du temps. C'est un filet, pas un rempart.

## Checklist à retenir

Trois vérifications suffisent pour couvrir l'essentiel de ce risque : désactiver `expose_php` dans la configuration PHP, appliquer `ServerTokens Prod` et `ServerSignature Off` sur Apache ou `server_tokens off` sur Nginx, et confirmer par une commande `curl -I` périodique que rien ne réapparaît après un changement d'infrastructure. Ce n'est pas une mesure de sécurité à elle seule, mais elle retire à un attaquant en phase de reconnaissance une part significative des informations qu'il obtiendrait autrement gratuitement, avant même d'avoir tenté quoi que ce soit.
