Offre Durée limitée : -10% sur tout le site* avec le code WELCOME10

Installer PHP-FPM sécurisé sur un VPS Linux : la configuration post-PHP2Shell

Mis à jour le 2 novembre 2026 23 min de lecture 13 sections

PHP-FPM et la crise PHP2Shell : pourquoi durcir maintenant

Le 21 octobre 2026, l'équipe PHP a publié des correctifs d'urgence pour deux vulnérabilités critiques cotées CVSS v4.0 9.2 : CVE-2026-109618 (exécution de code à distance via corruption mémoire lors d'un dépassement de la limite memory_limit) et CVE-2026-109619 (exécution de code via état global résiduel après libération de mémoire entre deux requêtes sur le même processus worker). Baptisées collectivement PHP2Shell, ces failles touchent tous les serveurs web qui exécutent des scripts PHP : PHP-FPM, mod_php sur le serveur Apache, php-cgi, FrankenPHP et LiteSpeed. Une seule requête HTTP non authentifiée suffit à déclencher l'exploitation, avant même que le code applicatif ne s'exécute. Des attaques actives ont été observées dès le 17 octobre 2026, soit quatre jours avant la publication des correctifs. Le CISA a ajouté les deux CVE à son catalogue KEV le 26 octobre 2026, confirmant une exploitation active dans la nature (source : Arctic Wolf).

Deux jours après les correctifs, PHP a attribué un troisième identifiant : CVE-2026-115560, un vecteur d'exécution de code à distance lié à session.upload_progress. Ce troisième vecteur n'a pas encore de correctif officiel : PHP recommande de désactiver session.upload_progress.enabled jusqu'à la prochaine version de maintenance. Concrètement, le mécanisme d'exploitation de PHP2Shell repose sur l'envoi de requêtes HTTP surdimensionnées (formulaires multipart de plus de 100 Mo ou champs profondément imbriqués) qui provoquent un dépassement de la mémoire allouée au processus PHP. Lors du nettoyage de la mémoire après l'erreur fatale, le moteur PHP interprète un état corrompu comme des structures de données valides, ce qui permet à l'attaquant de déclencher l'exécution de fonctions arbitraires sur le serveur.

Un guide d'audit PHP2Shell pour conteneurs Docker est déjà publié sur ElypseCloud. Mais beaucoup d'administrateurs de VPS Linux font tourner PHP-FPM directement sur le système d'exploitation, sans conteneurisation Docker. Ce tutoriel couvre l'installation native d'une version corrigée de PHP, le durcissement du fichier de configuration php.ini, la configuration d'un pool FPM isolé en socket Unix avec chroot, le couplage avec le serveur HTTP NGINX (et l'alternative Apache), la sécurisation des connexions aux bases de données et le monitoring des erreurs PHP sur votre serveur. Que vous soyez administrateur système indépendant ou client d'un hébergeur qui vous laisse la main sur les configurations système, chaque étape de ce guide s'applique à un VPS sous Ubuntu ou Debian.

Installer la version PHP corrigée (packages)

Les versions corrigées sont PHP 8.2.35, 8.3.36, 8.4.27 et 8.5.12, publiées le 21 octobre 2026. Toute version antérieure sur ces branches est vulnérable aux deux CVE critiques. Les branches PHP 8.1 et antérieures (7.4, 8.0) ne sont plus maintenues par le projet PHP : des backports minimaux sont disponibles via les distributions Linux ou les fournisseurs de support étendu, mais si votre serveur PHP utilise encore PHP 8.1 ou une version plus ancienne, la migration vers PHP 8.3 ou 8.4 est fortement recommandée pour bénéficier des correctifs de sécurité officiels. Vérifiez la version du package PHP installé sur votre VPS Linux :

php -v

Sur Ubuntu 22.04 / 24.04 ou Debian 12 avec le dépôt Ondrej Sury (PPA de référence pour les packages PHP récents), mettez à jour les paquets du serveur :

sudo apt update
sudo apt install --only-upgrade php8.3-fpm php8.3-cli php8.3-common

Adaptez php8.3 à votre branche (php8.2, php8.4). Si le dépôt Ondrej n'est pas encore configuré sur votre serveur Linux, ajoutez-le puis installez les packages PHP nécessaires, y compris les modules PHP courants pour les applications web :

sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php8.3-fpm php8.3-cli php8.3-mbstring php8.3-curl php8.3-xml php8.3-mysql

Le package php8.3-mysql fournit le module PHP pour les connexions à MySQL et MariaDB, le moteur de bases de données le plus déployé avec PHP. Pour les applications qui utilisent d'autres systèmes de gestion de bases de données, installez les modules correspondants (php8.3-pgsql pour PostgreSQL, php8.3-sqlite3 pour SQLite). L'extension php8.3-mbstring est indispensable au traitement correct des caractères UTF-8 dans les applications PHP modernes.

Après installation du package, confirmez que la version corrigée est en place sur votre serveur :

php -v
# Doit afficher 8.3.36 ou supérieur

Pour configurer les mises à jour automatiques de sécurité sur Ubuntu et ne plus rater un correctif critique pour votre infrastructure, consultez notre guide dédié.

Durcir php.ini : disable_functions, open_basedir et directives de sécurité

Même avec une version corrigée, un fichier de configuration php.ini permissif laisse la porte ouverte à l'exploitation de futures failles PHP. Le fichier php.ini de PHP-FPM se trouve généralement dans /etc/php/8.3/fpm/php.ini sur Debian et Ubuntu. Plusieurs directives de configuration réduisent drastiquement la surface d'attaque du serveur PHP et renforcent la sécurité de l'ensemble de l'hébergement web.

disable_functions : bloquer les fonctions d'exécution système

La directive disable_functions interdit l'appel de fonctions PHP dangereuses par les scripts. Sur un serveur web de production qui traite des requêtes HTTP, les fonctions d'exécution de commandes système ne sont presque jamais nécessaires au code applicatif. Ajoutez dans php.ini :

disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,pcntl_fork,putenv

Si votre application PHP (WordPress, Laravel, Symfony) utilise proc_open pour Composer ou un processus interne du framework, retirez-la de la liste. Testez votre application après chaque modification de la configuration du serveur PHP pour ne pas casser le fonctionnement de vos scripts.

open_basedir : restreindre l'accès au système de fichiers

open_basedir restreint les chemins du système de fichiers auxquels les scripts PHP peuvent accéder. Un script compromis sur le serveur ne pourra pas lire /etc/passwd ni écrire dans /tmp global :

open_basedir = /srv/www/monsite:/tmp/php-monsite

Créez un répertoire temporaire dédié par site hébergé plutôt que d'utiliser /tmp global, ce qui empêche un site compromis d'accéder aux fichiers temporaires d'un autre site sur le même serveur. Cette isolation au niveau du système de fichiers complète celle fournie par les pools PHP-FPM séparés.

session.upload_progress : mitigation de CVE-2026-115560

L'équipe PHP et le NCSC néerlandais recommandent de désactiver session.upload_progress comme mesure de protection contre le troisième vecteur d'attaque CVE-2026-115560. Cette fonctionnalité de suivi de la progression des téléversements de fichiers, rarement utilisée par les applications web modernes, intervient directement dans le mécanisme d'exploitation de PHP2Shell : l'attaquant utilise le traitement de la session d'upload pour injecter des données malveillantes dans l'état global du processus PHP. Ajoutez dans php.ini ou dans la configuration du pool FPM :

session.upload_progress.enabled = 0

Maintenez cette directive à 0 tant que PHP n'a pas publié de correctif pour CVE-2026-115560. La prochaine version de maintenance PHP devrait consolider la correction.

memory_limit et post_max_size : limiter les requêtes surdimensionnées

L'exploitation de CVE-2026-109618 repose sur le dépassement de la valeur memory_limit pour déclencher une corruption de mémoire. Ajustez ces deux directives pour limiter la taille des données que le serveur PHP accepte par requête :

memory_limit = 128M
post_max_size = 32M
upload_max_filesize = 16M
max_input_vars = 1000
max_input_nesting_level = 64

La directive max_input_vars limite le nombre de variables dans une requête POST, et max_input_nesting_level restreint la profondeur d'imbrication des tableaux. Ces deux limites réduisent la capacité d'un attaquant à construire les requêtes multipart surdimensionnées nécessaires à l'exploitation de PHP2Shell. Adaptez memory_limit aux besoins réels de votre application : une valeur trop basse empêche les scripts légitimes de fonctionner, une valeur trop haute facilite l'exploitation.

Autres directives de durcissement du serveur PHP

expose_php = Off
display_errors = Off
log_errors = On
error_log = /var/log/php/fpm-error.log
allow_url_fopen = Off
allow_url_include = Off
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1

expose_php = Off supprime l'en-tête X-Powered-By: PHP/x.x.x qui révèle la version exacte de PHP aux scanners automatiques qui sondent votre serveur. display_errors = Off empêche l'affichage des erreurs PHP aux visiteurs du site (les erreurs restent enregistrées dans les fichiers de logs du serveur). allow_url_include = Off bloque l'inclusion de fichiers distants via HTTP, un vecteur classique d'injection de code malveillant dans les scripts PHP. Les directives session.cookie_httponly et session.cookie_secure protègent les cookies de session contre le vol via JavaScript (XSS) et forcent leur transmission uniquement en HTTPS.

Configurer un pool PHP-FPM isolé

PHP-FPM (FastCGI Process Manager) permet de créer plusieurs pools de processus, chacun avec son propre utilisateur système, son socket Unix et ses restrictions de sécurité. Cette isolation des processus limite l'impact d'une compromission : un site piraté ne peut pas accéder aux fichiers d'un autre site hébergé sur le même VPS. C'est le principe de base de l'architecture multi-sites sécurisée pour tout hébergeur ou administrateur système qui gère plusieurs applications web sur un même serveur.

Créez un utilisateur système dédié au site. Cet utilisateur n'a pas de shell de connexion, ce qui empêche un attaquant d'obtenir un accès interactif au terminal via ce compte :

sudo useradd -r -s /usr/sbin/nologin -d /srv/www/monsite www-monsite

Créez le fichier de configuration du pool dans /etc/php/8.3/fpm/pool.d/monsite.conf :

[monsite]
user = www-monsite
group = www-monsite
listen = /run/php/monsite.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 4
pm.max_requests = 500

; Durcissement au niveau du pool
php_admin_value[open_basedir] = /srv/www/monsite:/tmp/php-monsite
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,pcntl_fork,putenv
php_admin_value[upload_tmp_dir] = /tmp/php-monsite
php_admin_value[session.save_path] = /tmp/php-monsite/sessions
php_admin_value[error_log] = /var/log/php/monsite-error.log
php_admin_flag[log_errors] = on
php_admin_value[session.upload_progress.enabled] = 0

Les directives php_admin_value et php_admin_flag ne peuvent pas être écrasées par un fichier .user.ini dans le répertoire du site. C'est la différence avec php_value : un attaquant qui dépose un .user.ini ne pourra pas réactiver les fonctions bloquées. La directive pm.max_requests = 500 force le recyclage des processus worker après 500 requêtes, ce qui limite la persistance d'un état corrompu en mémoire (le vecteur exploité par CVE-2026-109619).

Créez les répertoires nécessaires et appliquez les permissions de fichier :

sudo mkdir -p /tmp/php-monsite/sessions /var/log/php
sudo chown www-monsite:www-monsite /tmp/php-monsite /tmp/php-monsite/sessions
sudo chmod 700 /tmp/php-monsite /tmp/php-monsite/sessions

Chroot du pool FPM

Le chroot enferme le processus PHP-FPM dans un répertoire racine virtuel. Depuis un pool chrooté, le processus PHP ne voit pas le reste du système de fichiers du VPS. Ajoutez dans la configuration du pool :

chroot = /srv/www/monsite
chdir = /

Le chroot PHP-FPM impose d'adapter les chemins d'accès : les librairies partagées, les fichiers de résolution DNS (/etc/resolv.conf) et les certificats TLS doivent être accessibles dans l'arborescence chrootée. Pour un site statique ou une application PHP simple, c'est un renforcement efficace de l'isolation du serveur. Pour une application complexe qui appelle des services externes (API, SMTP, serveur de base de données distant), le chroot demande davantage de configurations. Évaluez le rapport isolation/complexité selon votre usage.

Après toute modification de la config du pool, redémarrez le service PHP-FPM pour appliquer les changements de configuration :

sudo systemctl restart php8.3-fpm

Coupler NGINX et PHP-FPM en socket Unix

NGINX est le serveur HTTP le plus utilisé avec PHP-FPM pour l'hébergement web de sites PHP. Le socket Unix est préférable à une connexion TCP (127.0.0.1:9000 sur localhost) : il ne traverse pas la pile réseau du système d'exploitation, n'est pas exposable par erreur sur une adresse IP publique, et les permissions de fichier du socket contrôlent quels processus peuvent s'y connecter. Configurez le virtual host (bloc server) NGINX pour utiliser le socket du pool. Remplacez monsite.example.com par votre nom de domaine :

server {
    listen 80;
    server_name monsite.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name monsite.example.com;

    root /srv/www/monsite/public;
    index index.php;

    ssl_certificate     /etc/letsencrypt/live/monsite.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/monsite.example.com/privkey.pem;

    # Limiter la taille des requêtes (mitigation PHP2Shell)
    client_max_body_size 32m;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/monsite.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

Le premier bloc server écoute sur le port 80 et effectue une redirection 301 permanente vers HTTPS. La directive client_max_body_size 32m limite la taille des requêtes HTTP acceptées par NGINX, ce qui ajoute une couche de filtrage en amont du serveur PHP contre les requêtes surdimensionnées utilisées dans l'exploitation de PHP2Shell. Le bloc location ~ /\.(?!well-known) interdit l'accès aux fichiers cachés (.env, .git, .htaccess) sauf le répertoire .well-known utilisé par Let's Encrypt. Pour la mise en place de vos certificats TLS générés par OpenSSL et signés par Let's Encrypt, consultez notre guide Certbot et Let's Encrypt.

Si vous utilisez NGINX comme reverse proxy devant plusieurs applications web, notre guide NGINX reverse proxy détaille la configuration multi-sites avec plusieurs virtual hosts sur un même serveur.

Testez la configuration NGINX puis redémarrez les services du serveur :

sudo nginx -t
sudo systemctl restart php8.3-fpm
sudo systemctl restart nginx

PHP-FPM avec le serveur Apache : migrer depuis mod_php

Si votre VPS utilise le serveur HTTP Apache plutôt que NGINX, la configuration post-PHP2Shell est tout aussi importante. Beaucoup de serveurs Apache utilisent encore mod_php (le module Apache qui exécute les scripts PHP dans le processus du serveur web lui-même). L'équipe de sécurité PHP et le NCSC néerlandais identifient mod_php comme la configuration la plus à risque face à PHP2Shell, avec un score CVSS v4.0 de 9.2 : l'exploitation se déclenche avant même que le code applicatif ne s'exécute, et le processus Apache compromise a les privilèges du serveur web entier. Migrer vers PHP-FPM sur Apache isole le processus d'exécution PHP du serveur web et réduit considérablement la surface d'attaque.

Désactivez le module PHP intégré à Apache et activez le module proxy FastCGI :

sudo a2dismod php8.3
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm

Cette configuration indique au serveur Apache de transmettre les requêtes PHP au service PHP-FPM via le protocole FastCGI et le socket Unix, au lieu de les traiter dans son propre processus. Vérifiez que le module Apache proxy_fcgi est bien chargé sur votre serveur :

sudo apachectl -M | grep proxy_fcgi

Si vous gérez des virtual hosts Apache pour plusieurs noms de domaine, configurez chaque virtual host pour pointer vers son propre pool PHP-FPM. Dans /etc/apache2/sites-available/monsite.conf :

<VirtualHost *:443>
    ServerName monsite.example.com
    DocumentRoot /srv/www/monsite/public

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/monsite.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/monsite.example.com/privkey.pem

    # Limiter la taille des requêtes (mitigation PHP2Shell)
    LimitRequestBody 33554432

    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/monsite.sock|fcgi://localhost"
    </FilesMatch>

    <Directory /srv/www/monsite/public>
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

La directive SetHandler transmet chaque requête PHP vers le socket Unix du pool FPM. Le chemin fcgi://localhost est une convention de syntaxe du module proxy FastCGI, aucune connexion TCP n'est ouverte. AllowOverride None désactive le traitement des fichiers .htaccess dans le répertoire du site, ce qui améliore les performances du serveur et empêche un attaquant de modifier la configuration Apache depuis un répertoire compromis. La directive LimitRequestBody restreint la taille des requêtes HTTP, comme client_max_body_size dans NGINX.

Activez le virtual host, testez la config Apache et redémarrez le service du serveur :

sudo a2ensite monsite.conf
sudo apachectl configtest
sudo systemctl restart apache2

Que vous choisissiez NGINX ou le serveur Apache, le pool PHP-FPM et le durcissement du fichier php.ini restent strictement identiques. Seule la configuration du serveur web change.

Sécuriser les connexions aux bases de données

La plupart des applications PHP (WordPress, Nextcloud, Laravel) se connectent à un serveur de bases de données MySQL ou MariaDB. Après PHP2Shell, sécuriser ces connexions est essentiel : un attaquant qui a obtenu une exécution de code sur le serveur PHP via les CVE critiques peut pivoter vers la base de données si les accès ne sont pas correctement restreints.

Connexion par socket Unix plutôt que TCP

Comme pour PHP-FPM, privilégiez le socket Unix pour les connexions à MariaDB ou MySQL sur le même serveur. Dans le fichier php.ini ou la configuration du pool :

pdo_mysql.default_socket = /run/mysqld/mysqld.sock
mysqli.default_socket = /run/mysqld/mysqld.sock

La connexion par socket Unix ne passe pas par la pile réseau TCP/IP du système d'exploitation. Elle n'est pas exposable sur une adresse IP et ne peut pas être interceptée par un outil de capture réseau. Pour installer et configurer le serveur MariaDB sur votre VPS Linux, consultez notre guide d'installation MariaDB.

Utilisateur de base de données dédié par application

Créez un utilisateur MySQL/MariaDB spécifique pour chaque application PHP hébergée sur le serveur, avec les permissions minimales nécessaires. Ne jamais utiliser le compte root de la base de données dans la configuration d'une application web :

CREATE USER 'monsite_app'@'localhost' IDENTIFIED BY 'mot_de_passe_fort';
GRANT SELECT, INSERT, UPDATE, DELETE ON monsite_db.* TO 'monsite_app'@'localhost';
FLUSH PRIVILEGES;

Le compte 'monsite_app'@'localhost' ne peut se connecter que depuis le serveur local et n'a accès qu'à la base de données de l'application. Un attaquant qui compromet une application PHP ne pourra pas accéder aux bases de données des autres sites hébergés sur le même serveur.

phpMyAdmin : restreindre ou supprimer l'accès

phpMyAdmin est l'interface web de gestion de bases de données la plus déployée avec PHP. C'est aussi une cible privilégiée des scanners automatiques qui sondent les serveurs exposés sur Internet. Si phpMyAdmin est installé sur votre serveur, restreignez son accès par adresse IP dans la configuration NGINX ou Apache :

# NGINX
location /phpmyadmin {
    allow 203.0.113.50;
    deny all;
}

# Apache
<Directory /usr/share/phpmyadmin>
    Require ip 203.0.113.50
</Directory>

Remplacez 203.0.113.50 par votre adresse IP d'administration. Si vous n'avez pas besoin de phpMyAdmin en production, désinstallez-le et utilisez le client en ligne de commande (mysql ou mariadb) via une connexion SSH. Moins d'outils exposés sur le serveur, moins de surface d'attaque.

Pare-feu, FTP et accès SSH

Le durcissement de PHP-FPM ne protège que le canal web. Le firewall (pare-feu) du VPS doit compléter la protection en restreignant les connexions réseau entrantes aux seuls ports nécessaires sur le serveur. Avec UFW sur Ubuntu ou Debian :

sudo ufw default deny incoming
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP (redirection vers HTTPS)
sudo ufw allow 443/tcp   # HTTPS
sudo ufw enable

Pour une configuration plus fine du pare-feu avec nftables, consultez notre guide nftables pour VPS Linux.

Désactiver FTP : utiliser SSH et SFTP

Le protocole FTP transmet les identifiants et les fichiers en clair sur le réseau. Si un service FTP (vsftpd, ProFTPD) est actif sur votre serveur, désactivez-le et utilisez SFTP (transfert de fichiers via le protocole SSH) :

sudo systemctl stop vsftpd
sudo systemctl disable vsftpd

SFTP est intégré au serveur SSH (OpenSSH) : aucun package supplémentaire n'est nécessaire. Vos connexions de transfert de fichiers sont chiffrées par le même canal SSH. Pour sécuriser l'accès SSH à votre VPS, consultez notre guide SSH sur VPS Linux.

Vérifiez les ports ouverts sur votre serveur pour confirmer que seuls les services nécessaires écoutent. Notre guide ss pour lister les ports détaille la procédure complète.

Détecter une tentative d'exploitation PHP2Shell dans les logs

La mise à jour du serveur PHP et le durcissement de la configuration réduisent le risque, mais il est essentiel de surveiller les journaux de logs pour détecter une tentative d'exploitation, réussie ou non. Les équipes de recherche en sécurité (Datadog Security Labs, Arctic Wolf) ont identifié des indicateurs spécifiques à PHP2Shell dans les logs du serveur.

Indicateurs dans les logs d'erreur PHP

Les messages suivants dans le fichier de log d'erreur PHP signalent une possible tentative d'exploitation :

  • Fatal error: Allowed memory size of ... bytes exhausted ... in Unknown on line 0 : la mention "Unknown on line 0" est caractéristique d'un dépassement mémoire déclenché avant l'exécution du script applicatif, ce qui correspond au vecteur CVE-2026-109618.
  • Des erreurs de segmentation (segfault) répétées dans les processus worker PHP-FPM ou Apache, visibles dans journalctl -u php8.3-fpm ou dans le journal système (/var/log/syslog).
  • Des erreurs de décodage de session (session_decode) associées à des dépassements mémoire dans les mêmes requêtes.

Indicateurs dans les logs d'accès du serveur web

Analysez les requêtes HTTP anormales dans les logs d'accès NGINX ou Apache :

  • Des requêtes POST de taille inhabituellement grande (supérieures à 100 Mo) envoyées vers des endpoints PHP standard.
  • Des requêtes contenant un nombre anormal de sections multipart (plus de 900 par requête) ou des champs avec des crochets profondément imbriqués (a[b][c][d][e]...).
  • La présence du cookie PHPSESSID avec des valeurs contenant des octets nuls ou des séquences encodées inhabituelles.

Surveillez les processus du serveur PHP pour détecter des comportements anormaux :

# Rechercher des processus worker PHP qui auraient lancé un shell
ps aux | grep -E 'php-fpm.*sh|www-data.*/bin/(ba)?sh'

# Vérifier les erreurs mémoire récentes dans les logs système
sudo journalctl -u php8.3-fpm --since "24 hours ago" | grep -i "memory\|segfault\|signal"

Si vous détectez des indicateurs suspects, consultez notre guide de détection forensique post-PHP2Shell pour une analyse complète. Pour une surveillance automatisée et le blocage des adresses IP malveillantes, CrowdSec analyse les logs en temps réel.

Vérifier que le durcissement est actif sur le serveur

Créez un fichier de test temporaire dans le répertoire web de votre site pour confirmer que les restrictions sont bien appliquées par la configuration du serveur :

<?php
// Fichier de test - à supprimer après vérification
echo 'PHP version : ' . phpversion() . "\n";
echo 'disable_functions : ' . ini_get('disable_functions') . "\n";
echo 'open_basedir : ' . ini_get('open_basedir') . "\n";
echo 'expose_php : ' . ini_get('expose_php') . "\n";
echo 'allow_url_include : ' . ini_get('allow_url_include') . "\n";
echo 'session.upload_progress.enabled : ' . ini_get('session.upload_progress.enabled') . "\n";
echo 'memory_limit : ' . ini_get('memory_limit') . "\n";
echo 'post_max_size : ' . ini_get('post_max_size') . "\n";

Appelez ce fichier depuis votre navigateur ou avec curl depuis le serveur. Vérifiez que disable_functions contient bien votre liste de fonctions bloquées, que open_basedir est défini et que expose_php est à Off. Supprimez ce fichier immédiatement après vérification : un phpinfo() ou un script de diagnostic exposé sur un serveur de production est un vecteur de fuite d'information sur la configuration PHP.

Vérifiez aussi que l'en-tête HTTP ne révèle plus la version PHP installée sur votre serveur :

curl -I https://monsite.example.com/ | grep -i x-powered-by
# Aucun résultat attendu

Vous pouvez également vérifier le certificat TLS de votre nom de domaine avec OpenSSL. Notre guide de vérification de certificat TLS avec openssl détaille les commandes.

Monitoring des erreurs PHP et alertes du serveur

Un serveur PHP durci sans monitoring des logs est un serveur qui se fait compromettre en silence. Configurez la rotation des fichiers de logs PHP pour éviter qu'ils ne saturent le disque de votre VPS :

sudo nano /etc/logrotate.d/php-fpm-monsite
/var/log/php/monsite-error.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        /usr/lib/php/php8.3-fpm-reopenlogs
    endscript
}

Surveillez les erreurs du serveur PHP en temps réel avec journalctl :

sudo journalctl -u php8.3-fpm -f

Pour aller plus loin dans la détection d'intrusion sur votre infrastructure, CrowdSec analyse les logs en temps réel et bloque automatiquement les adresses IP malveillantes. Combiné à Fail2ban pour SSH, vous couvrez les deux principaux vecteurs d'attaque sur un VPS Linux : les requêtes HTTP vers le serveur web et les tentatives de connexion SSH par force brute.

Le statut du service PHP-FPM se vérifie avec la commande systemctl :

sudo systemctl status php8.3-fpm

Activez la page de statut FPM dans la configuration du pool pour surveiller le nombre de processus actifs, les requêtes en file d'attente et la mémoire consommée par le serveur PHP :

pm.status_path = /fpm-status

Protégez cet endpoint dans la config NGINX ou Apache pour qu'il ne soit accessible que depuis localhost ou vos adresses IP d'administration :

location = /fpm-status {
    fastcgi_pass unix:/run/php/monsite.sock;
    include fastcgi_params;
    allow 127.0.0.1;
    deny all;
}

Tableau récapitulatif des réglages de sécurité du serveur PHP

RéglageFichier de configValeur recommandéeObjectif
Version PHPPackage système8.3.36+ / 8.4.27+Corriger CVE-2026-109618 et CVE-2026-109619 (CVSS 9.2)
disable_functionsphp.ini ou pool.confexec, passthru, shell_exec, system, proc_open, popenBloquer l'exécution de commandes système par les scripts PHP
open_basedirpool.conf (php_admin_value)/srv/www/monsite:/tmp/php-monsiteRestreindre l'accès au système de fichiers du serveur
session.upload_progressphp.ini ou pool.conf0 (désactivé)Mitigation CVE-2026-115560 (troisième vecteur PHP2Shell)
memory_limitphp.ini128MLimiter la mémoire par processus PHP (mitigation CVE-2026-109618)
post_max_sizephp.ini32MLimiter la taille des requêtes POST vers le serveur
max_input_varsphp.ini1000Limiter le nombre de variables par requête HTTP
expose_phpphp.iniOffMasquer la version PHP dans les en-têtes HTTP du serveur
display_errorsphp.iniOffNe pas afficher les erreurs PHP aux visiteurs du site
allow_url_includephp.iniOffBloquer l'inclusion de scripts PHP distants via HTTP
Socket Unixpool.conf + config serveur web/run/php/monsite.sockPas d'exposition réseau du listener PHP-FPM
Utilisateur dédiépool.confwww-monsiteIsolation des processus par site sur le serveur
pm.max_requestspool.conf500Recycler les workers pour limiter la persistance en mémoire
Chrootpool.conf/srv/www/monsiteEmpêcher PHP de voir le reste du système de fichiers
Serveur web (NGINX/Apache)nginx.conf ou apache2.confRedirection HTTP vers HTTPS, virtual host TLSChiffrer toutes les connexions avec un certificat TLS
client_max_body_sizenginx.conf32mFiltrer les requêtes surdimensionnées en amont de PHP
Firewall (UFW)UFW / nftablesdeny incoming, allow 22/80/443Bloquer les connexions non autorisées au serveur
FTPsystemdDésactivéSupprimer le transfert de fichiers en clair, utiliser SSH/SFTP
MariaDB/MySQL socketphp.ini/run/mysqld/mysqld.sockConnexion base de données sans exposition réseau
phpMyAdminconfig serveur webAccès restreint par IP ou désinstalléRéduire la surface d'attaque de l'interface de gestion
pm.status_pathpool.conf + config serveur web/fpm-status (accès restreint par IP)Monitoring des processus PHP-FPM du serveur

Aller plus loin dans la sécurisation du serveur

Ce guide couvre le durcissement natif de PHP-FPM sur un VPS Linux avec NGINX ou le serveur Apache, dans le contexte des vulnérabilités critiques PHP2Shell. Pour compléter la sécurisation de votre serveur et de votre infrastructure d'hébergement :

FAQ

Mon VPS est-il vulnérable à PHP2Shell si j'utilise PHP-FPM ?

Oui. PHP2Shell (CVE-2026-109618 et CVE-2026-109619) touche toutes les installations PHP exposées au web, y compris PHP-FPM, mod_php, php-cgi et LiteSpeed. Les versions corrigées sont PHP 8.2.35, 8.3.36, 8.4.27 et 8.5.12. Vérifiez votre version avec la commande php -v et mettez à jour immédiatement si vous êtes sur une version antérieure.

Quelle est la différence entre disable_functions dans php.ini et dans pool.conf ?

Les deux empêchent l'appel des fonctions listées. La différence est que php_admin_value[disable_functions] dans pool.conf ne peut pas être écrasé par un fichier .user.ini déposé dans le répertoire du site. Un attaquant qui obtient un accès en écriture ne pourra pas réactiver les fonctions bloquées au niveau du pool.

Le chroot PHP-FPM casse-t-il mon application ?

Le chroot restreint la visibilité du système de fichiers aux répertoires sous la racine du chroot. Une application simple (site statique, WordPress avec les fichiers dans le même répertoire) fonctionne. Une application qui appelle des binaires externes, des sockets ou des fichiers situés hors du chroot nécessite des ajustements (montages bind ou copie des fichiers nécessaires).

Pourquoi utiliser un socket Unix plutôt que TCP pour PHP-FPM ?

Un socket Unix ne passe pas par la pile réseau TCP/IP du noyau Linux, il est légèrement plus rapide et ne risque pas d'être exposé sur une interface réseau publique par erreur. Les permissions de fichier du socket contrôlent quels processus peuvent s'y connecter, ce qui ajoute une couche de contrôle d'accès absente avec TCP.

Comment savoir quelles fonctions désactiver sans casser mon application ?

Commencez par la liste complète recommandée (exec, passthru, shell_exec, system, proc_open, popen). Si votre application échoue au démarrage, consultez les logs d'erreur PHP pour identifier la fonction bloquée, puis retirez-la de la liste. Les frameworks PHP (Laravel, Symfony) utilisent parfois proc_open pour Composer ou les workers de file d'attente.

Faut-il aussi durcir PHP si mon VPS est derrière un pare-feu ?

Oui. Un pare-feu (firewall) protège contre les connexions réseau non autorisées, mais PHP2Shell s'exploite via une requête HTTP légitime sur le port 443 ou 80. Le firewall laisse passer le trafic web normal. Le durcissement de PHP (version corrigée, disable_functions, open_basedir) protège contre les attaques qui passent par le canal web autorisé.

Faut-il migrer d'Apache mod_php vers PHP-FPM ?

Oui, c'est recommandé. Le module Apache mod_php exécute les scripts PHP dans le processus du serveur web Apache, ce qui est identifié comme la configuration la plus à risque par le NCSC néerlandais. PHP-FPM isole l'exécution PHP dans un processus séparé avec son propre utilisateur système, ses propres configurations et restrictions. La migration se fait en désactivant le module PHP d'Apache (a2dismod php8.3) et en activant le module proxy FastCGI (a2enmod proxy_fcgi). Le pool FPM et le fichier php.ini durci restent identiques que vous utilisiez NGINX ou le serveur Apache.

Comment sécuriser phpMyAdmin sur un serveur PHP-FPM ?

Restreignez l'accès à phpMyAdmin par adresse IP dans la configuration de votre serveur web (NGINX ou Apache). Dans NGINX, utilisez les directives allow et deny dans le bloc location /phpmyadmin. Dans Apache, utilisez la directive Require ip dans le virtual host. Si phpMyAdmin n'est pas indispensable en production, désinstallez-le et utilisez le client en ligne de commande MySQL/MariaDB via une connexion SSH chiffrée.

Faut-il désactiver FTP sur un serveur PHP ?

Oui. Le protocole FTP transmet les identifiants et les fichiers en clair sur le réseau. Utilisez SFTP (intégré au serveur SSH) pour le transfert de fichiers. Désactivez le service FTP (vsftpd, ProFTPD) avec systemctl disable et vérifiez avec ss ou notre guide de listing des ports en écoute qu'aucun service FTP n'écoute sur les ports 20 et 21.

Qu'est-ce que CVE-2026-115560 et quel est le lien avec PHP2Shell ?

CVE-2026-115560 est un troisième vecteur d'exécution de code à distance dans PHP, attribué le 23 octobre 2026, deux jours après les correctifs PHP2Shell. Il exploite une interaction entre la sérialisation de session et la fonctionnalité session.upload_progress. Contrairement aux deux premiers CVE, il n'a pas encore de correctif officiel. La mitigation recommandée par l'équipe PHP est de désactiver session.upload_progress.enabled dans le fichier php.ini ou la configuration du pool FPM.

Comment détecter une tentative d'exploitation PHP2Shell dans les logs du serveur ?

Recherchez dans les logs d'erreur PHP le message "Fatal error: Allowed memory size exhausted in Unknown on line 0", qui signale un dépassement mémoire déclenché avant l'exécution du code applicatif. Vérifiez aussi les erreurs de segmentation (segfault) répétées dans les processus PHP-FPM via journalctl -u php8.3-fpm. Dans les logs d'accès du serveur web, les requêtes POST anormalement volumineuses (plus de 100 Mo) ou contenant des centaines de sections multipart sont des indicateurs suspects.

Quelle est la différence entre PHP-FPM et mod_php pour la sécurité du serveur ?

mod_php exécute les scripts PHP directement dans le processus du serveur web Apache. Si PHP est compromis, l'attaquant hérite des privilèges du serveur Apache entier. PHP-FPM (FastCGI Process Manager) isole l'exécution PHP dans des processus séparés, chacun avec son propre utilisateur système, ses propres restrictions et son propre pool de configuration. Cette isolation limite l'impact d'une compromission à un seul site. Le NCSC néerlandais identifie mod_php comme la configuration la plus à risque face à PHP2Shell.