On est tous un peu paranos quand il s'agit de nos petites applications auto-hébergées. Surtout quand on fait du PHP, une cible de choix pour les petits malins qui cherchent la faille. Un pare-feu, c'est bien, ça protège des attaques réseau basiques, mais ça ne voit pas ce qui se passe dans les requêtes HTTP. Et là, on parle d'injections SQL, de XSS, d'inclusion de fichiers... Bref, la couche application, c'est le ventre mou.
C'est là que ModSecurity entre en jeu. C'est un peu le videur costaud qui se poste devant votre application web, analyse chaque requête et décide si elle est digne d'entrer ou si elle doit aller voir ailleurs. Un pare-feu d'applications web (WAF) open-source, quoi. Et croyez-moi, pour nos homelabs ou nos petits serveurs, c'est un atout non négligeable.
ModSecurity, le videur de requêtes pour vos applications
ModSecurity, ou Modsec pour les intimes, n'est pas un simple pare-feu. Il opère à la couche 7 du modèle OSI, c'est-à-dire qu'il comprend le langage HTTP. Il ne regarde pas juste les ports ou les adresses IP, il décortique le contenu des requêtes et des réponses pour y débusquer les intentions malveillantes. SQLi, XSS, RFI, LFI, injection de commandes... la liste est longue. Il logue tout, et si on lui demande gentiment, il bloque aussi.
Historiquement développé par Ivan Ristić et maintenu par Trustwave SpiderLabs, le projet est passé sous la houlette de l'OWASP (Open Web Application Security Project) début 2024. C'est une bonne nouvelle, ça assure une maintenance communautaire et une intégration encore plus forte avec l'OWASP Core Rule Set (CRS), l'ensemble de règles génériques qui font la force de ModSecurity.
Pour Nginx, la version qui nous intéresse est libModSecurity v3, accompagnée de son connecteur spécifique. C'est la version moderne, plus performante et plus souple que l'ancienne v2.
Comment ça marche, ce truc ? L'architecture ModSecurity + Nginx
Avec Nginx, ModSecurity ne s'installe pas comme un module Apache classique. C'est une bibliothèque (libModSecurity) avec un connecteur Nginx séparé. En gros, Nginx est compilé pour inclure ce connecteur, qui fait le pont entre le serveur web et le moteur ModSecurity. Quand une requête arrive, Nginx la passe au moteur ModSecurity, qui l'analyse avec ses règles, et renvoie un verdict : laisser passer, bloquer, loguer, etc.
C'est transparent pour l'application PHP derrière. Elle ne voit qu'une requête "propre" (si elle passe le WAF) ou ne voit rien du tout (if elle est bloquée). L'avantage, c'est que ça ajoute une couche de sécurité sans avoir à toucher au code de votre application. Pratique quand on maintient des vieux projets ou des CMS.
Installer ModSecurity avec Nginx : la méthode "on met les mains dans le cambouis" (et en Docker, c'est pas si sorcier)
Alors oui, installer ModSecurity v3 avec Nginx, ce n'est pas un simple apt install (sauf si vous êtes sur Debian 12+ ou Ubuntu 24.04+, où un paquet libnginx-mod-http-modsecurity existe et simplifie pas mal les choses). Pour la plupart d'entre nous, ça implique de recompiler Nginx. Mais pas de panique, c'est faisable, surtout dans un contexte Dockerfile.
On va partir sur la compilation. Imaginez que vous construisez votre image Docker Nginx. Voici les étapes clés :
1. Préparer l'environnement et les dépendances
Il faut pas mal de trucs pour compiler. Pour une base Debian/Ubuntu, ça donne ça :
sudo apt update sudo apt install -y apt-utils autoconf automake build-essential git libcurl4-openssl-dev libgeoip-dev liblmdb-dev libpcre2-dev libtool libxml2-dev libyajl-dev pkgconf wget zlib1g-dev
2. Cloner et compiler libModSecurity
On récupère le code source de libModSecurity (la v3, donc) et on le compile. Le dépôt owasp-modsecurity/ModSecurity est le bon.
cd /usr/local/src git clone --depth 100 -b v3/master --single-branch https://github.com/owasp-modsecurity/ModSecurity cd ModSecurity sh build.sh ./configure make sudo make install
3. Cloner le connecteur ModSecurity-nginx
C'est le module qui va faire le lien entre Nginx et libModSecurity.
cd /usr/local/src git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git
4. Recompiler Nginx avec le module dynamique
C'est l'étape la plus délicate. Il faut télécharger les sources de votre version exacte de Nginx. Pour connaître les arguments de configuration de votre Nginx actuel, faites un nginx -V. Vous devrez les réutiliser.
cd /path/to/nginx-source-version ./configure --with-compat --add-dynamic-module=/usr/local/src/ModSecurity-nginx <vos_arguments_configure_nginx_existants> make modules sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules
Une fois le module compilé, on le copie dans le répertoire des modules de Nginx.
5. Charger le module dans nginx.conf
Il ne reste plus qu'à dire à Nginx de charger ce nouveau module. Ajoutez cette ligne tout en haut de votre /etc/nginx/nginx.conf :
load_module modules/ngx_http_modsecurity_module.so;
Redémarrez Nginx, et si tout va bien, il ne devrait pas hurler.
Pour ceux qui utilisent Debian 12+ ou Ubuntu 24.04+, la vie est plus simple. Un sudo apt install libnginx-mod-http-modsecurity modsecurity-crs et le tour est joué, le module est activé via /etc/nginx/modules-enabled/50-mod-http-modsecurity.conf et le CRS est installé. C'est la solution que je privilégierais si mon OS le permet.
Les règles du jeu : OWASP Core Rule Set (CRS)
ModSecurity sans règles, c'est comme un videur sans muscles. C'est l'OWASP Core Rule Set (CRS) qui lui donne sa force. C'est un ensemble de règles génériques, maintenues par l'OWASP, qui protègent contre la majorité des attaques du Top 10 de l'OWASP : injection SQL, XSS, inclusion de fichiers, etc.
Le CRS est intelligent, il utilise des "niveaux de paranoïa" (Paranoia Level, de PL1 à PL4). PL1 est le moins agressif, avec peu de faux positifs, mais une protection de base. PL4 est le plus strict, protégeant au maximum, mais augmentant le risque de bloquer des requêtes légitimes. Il faut trouver le juste milieu pour votre application.
Pour activer ModSecurity et le CRS, vous aurez une configuration Nginx qui ressemble à ça :
http {
# ...
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# ...
}
Et dans votre fichier /etc/nginx/modsec/main.conf (que vous devrez créer) :
SecRuleEngine On SecRequestBodyAccess On SecAuditLog /var/log/modsec_audit.log SecDebugLog /var/log/modsec_debug.log Include /etc/nginx/modsec/owasp-modsecurity-crs/crs-setup.conf Include /etc/nginx/modsec/owasp-modsecurity-crs/rules/*.conf # Exemple pour ajuster le niveau de paranoïa (ici PL1) # SecAction "id:900000,phase:1,nolog,pass,ctl:ruleEngine=On,ctl:auditEngine=On,ctl:auditLogParts=+E,ctl:hashEngine=On,ctl:hashKey=modsecurity,ctl:hashTime=300,ctl:requestBodyAccess=On,ctl:responseBodyAccess=On,setvar:tx.paranoia_level=1" # Le fichier crs-setup.conf contient déjà des directives pour le paranoia_level. # Généralement, on le configure directement dedans. Cherchez `SecRuleEngine` et `setvar:tx.paranoia_level` dans crs-setup.conf. # Par défaut, le CRS est en PL1. # Si vous voulez désactiver une règle spécifique (par exemple, la règle 920350 qui est un peu trop zélée) # SecRuleRemoveById 920350
Le fichier crs-setup.conf est là pour configurer le CRS, notamment le niveau de paranoïa. N'hésitez pas à jeter un œil à son contenu pour comprendre comment il fonctionne.
Protéger une app PHP : l'exemple concret
Une fois ModSecurity actif globalement, vous pouvez l'activer ou le désactiver par server ou location dans votre configuration Nginx. C'est super pratique pour ne pas impacter toutes vos applications d'un coup ou pour appliquer des règles spécifiques.
server {
listen 80;
server_name example.com;
modsecurity on; # Active ModSecurity pour ce serveur virtuel
modsecurity_rules_file /etc/nginx/modsec/main.conf; # Fichier de règles principal
location / {
root /var/www/html;
# modsecurity off; # On pourrait le désactiver ici si besoin
}
}
Quand vous déployez ModSecurity pour la première fois sur une application existante (surtout une application PHP type Laravel ou Symfony qui peut avoir des comportements un peu "spéciaux" pour un WAF), je vous conseille de commencer en mode détection seule :
SecRuleEngine DetectionOnly
Ça va loguer toutes les alertes sans bloquer les requêtes. Vous pourrez ainsi analyser les journaux (/var/log/modsec_audit.log est votre ami) et identifier les faux positifs avant de passer en SecRuleEngine On.
Les pièges à éviter et comment s'en sortir (les faux positifs, ce fléau)
Le plus gros problème avec ModSecurity et le CRS, c'est les faux positifs. Une requête tout à fait légitime peut être interprétée comme une attaque et bloquée. C'est frustrant, surtout quand votre application commence à renvoyer des 403 à tout bout de champ.
Le "tuning" est une étape obligatoire. Il faut analyser les logs, comprendre pourquoi une règle s'est déclenchée, et soit :
- Désactiver la règle spécifique avec
SecRuleRemoveById <ID_DE_REGLE>(à faire avec parcimonie). - Ajuster le niveau de paranoïa (
tx.paranoia_leveldanscrs-setup.conf) pour rendre le CRS moins agressif.
C'est un travail de longue haleine, mais essentiel pour que ModSecurity soit efficace sans casser votre application. Et oui, ça demande du temps. Les solutions "zero-config" comme Defensia sont sympas, mais elles n'ont pas la même granularité ni la même capacité à bloquer la première requête malveillante.
Autre point : ModSecurity inspecte chaque requête. Ça prend du CPU et un peu de RAM. Pour la plupart des homelabs, ce n'est pas un problème majeur, mais sur des serveurs très chargés, ça peut se sentir. On parle de 1 à 5ms de latence en plus par requête, ce qui est généralement acceptable.
Et après ? Les alternatives et l'avenir
ModSecurity v3 est en "mode maintenance" sous l'OWASP. Ça veut dire des correctifs, mais moins de nouvelles fonctionnalités. L'OWASP a un successeur spirituel, OWASP Coraza, écrit en Go. Il est plus moderne, plus rapide, et compatible avec le CRS. Si vous démarrez un nouveau projet ou si vous êtes fan de Go, c'est une piste à explorer sérieusement, surtout pour les architectures cloud-native.
Il y a aussi d'autres WAF open-source comme NAXSI pour Nginx, ou des approches plus avancées avec OpenResty et des scripts Lua. Mais ModSecurity reste une référence et une solution solide et éprouvée.
Mon avis, sans filtre
ModSecurity avec Nginx, c'est un peu comme mettre un antivol de pro sur votre vélo, même s'il ne vaut pas des milliers d'euros. C'est une protection supplémentaire, une barrière de plus pour les scripts kiddies et les scanners automatiques. L'installation peut être un peu fastidieuse si vous devez compiler Nginx, et le tuning des règles pour éviter les faux positifs demande du temps et de la patience. C'est le prix à payer pour une sécurité solide et open-source.
Est-ce que ça vaut le coup ? Oui, clairement. Surtout si vous hébergez des applications PHP qui gèrent des données sensibles ou qui sont exposées sur Internet. Ça ne remplace pas un bon code sécurisé et des mises à jour régulières, mais ça ajoute une couche de défense essentielle. Pour un homelabber qui aime mettre les mains dans le cambouis et comprendre ce qu'il déploie, c'est un excellent projet pour monter en compétence en sécurité web. Et puis, la satisfaction de voir les tentatives d'attaques bloquées dans les logs, ça n'a pas de prix !