ModSecurity + OWASP CRS : WAF pour Nginx

ModSecurity + OWASP CRS : WAF pour Nginx

Mettez un WAF (Web Application Firewall) devant vos sites web pour bloquer SQLi, XSS, RFI, scans, et exploits CVE. ModSecurity v3 + Core Rule Set OWASP, l'attelage open-source standard de l'industrie.

Introduction

Un site web est exposé en permanence à des centaines d'attaques automatisées : injections SQL, XSS, bots cherchant des CVE WordPress, etc.

ModSecurity intercepte les requêtes HTTP/S et les évalue contre un jeu de règles avant de les passer à votre application. Couplé au OWASP Core Rule Set (CRS), vous bloquez :

  • SQLi (SQL injection)
  • XSS (Cross-site scripting)
  • RFI / LFI (Remote / Local File Inclusion)
  • Command injection
  • Scanners (Nikto, sqlmap, etc.)
  • Exploits CVE connus (Log4Shell, Heartbleed, etc.)

Prérequis

  • Nginx installé (1.18+)
  • VPS Debian / Ubuntu
  • Accès root

Étape 1 : Installation

sudo apt update
sudo apt install -y libmodsecurity3 libmodsecurity-dev nginx-module-modsecurity

Activez le module dans /etc/nginx/nginx.conf :

load_module modules/ngx_http_modsecurity_module.so;

http {
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsec/main.conf;
    # ...
}

Étape 2 : Configuration de base

sudo mkdir -p /etc/nginx/modsec
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
sudo nano /etc/nginx/modsec/modsecurity.conf

Changez SecRuleEngine :

SecRuleEngine DetectionOnly

⚠️ Démarrez en DetectionOnly (log uniquement) pour identifier les faux positifs avant de passer en On (bloquant).

Étape 3 : Installer OWASP CRS

cd /etc/nginx/modsec
sudo git clone https://github.com/coreruleset/coreruleset.git
sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

Étape 4 : main.conf

sudo nano /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/coreruleset/crs-setup.conf
Include /etc/nginx/modsec/coreruleset/rules/*.conf

Étape 5 : Tester et activer

sudo nginx -t
sudo systemctl reload nginx

Test SQLi :

curl "http://votre-site.fr/?id=1' OR '1'='1"

Vérifiez les logs :

sudo tail -f /var/log/modsec_audit.log

Vous devriez voir l'attaque détectée.

Étape 6 : Tuner les faux positifs

Pendant quelques jours, laissez en DetectionOnly et analysez les logs :

sudo grep -E "MATCHES|Detected" /var/log/modsec_audit.log | head

Pour exclure une règle pour un site spécifique :

sudo nano /etc/nginx/sites-available/mon-site
server {
    location /admin/ {
        modsecurity_rules '
            SecRuleRemoveById 941100
            SecRuleRemoveById 942100
        ';
    }
}

Ou globalement, créez /etc/nginx/modsec/coreruleset/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf :

SecRule REQUEST_URI "@beginsWith /api/" "id:1001,phase:1,nolog,allow,ctl:ruleRemoveById=920420"

Étape 7 : Activer le mode blocage

Une fois les faux positifs réglés :

sudo nano /etc/nginx/modsec/modsecurity.conf
SecRuleEngine On
sudo systemctl reload nginx

ModSecurity bloque maintenant en HTTP 403.

Étape 8 : Niveaux d'agressivité (Paranoia Level)

CRS supporte 4 niveaux (1-4) :

  • PL1 : règles essentielles, peu de faux positifs (défaut)
  • PL2 : plus stricte
  • PL3 : strict, beaucoup de FP probables
  • PL4 : paranoid, à réserver à des contextes critiques
sudo nano /etc/nginx/modsec/coreruleset/crs-setup.conf
SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=2"

Étape 9 : Anomaly scoring

CRS utilise un système de score. Chaque règle déclenchée ajoute des points. Quand le score dépasse un seuil, la requête est bloquée :

SecAction "id:900110,phase:1,nolog,pass,t:none,
    setvar:tx.inbound_anomaly_score_threshold=5,
    setvar:tx.outbound_anomaly_score_threshold=4"

Réduisez le seuil pour être plus strict (3 au lieu de 5).

Étape 10 : Personnaliser les règles

Bloquer une IP :

SecRule REMOTE_ADDR "@ipMatch 1.2.3.4" "id:1000,phase:1,deny,status:403"

Bloquer un User-Agent :

SecRule REQUEST_HEADERS:User-Agent "@contains sqlmap" "id:1001,phase:1,deny,status:403"

Rate-limit sur /login :

SecAction "id:1002,phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},chain"
SecRule REQUEST_URI "@beginsWith /login" "chain"
SecAction "id:1003,setvar:ip.attempts=+1,expirevar:ip.attempts=60"
SecRule IP:attempts "@gt 5" "id:1004,deny,status:429"

Étape 11 : Performance

ModSecurity ajoute 5-15ms par requête en moyenne. Pour optimiser :

SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072

Limitez le scan à certaines requêtes :

location / {
    modsecurity on;
}

location /static/ {
    modsecurity off;  # bypass pour assets statiques
}

Étape 12 : Monitoring

Comptez les blocages par jour :

sudo grep "Access denied" /var/log/nginx/error.log | wc -l

Top des règles déclenchées :

sudo grep "Matched" /var/log/modsec_audit.log | grep -oP 'id "\d+"' | sort | uniq -c | sort -rn | head

Top des IPs bloquées :

sudo grep "deny" /var/log/nginx/error.log | grep -oP 'client: \S+' | sort | uniq -c | sort -rn | head

Dépannage

"modsecurity: SecRuleEngine On - failed"

Syntaxe invalide dans une règle. Vérifiez :

sudo nginx -t

L'erreur précise quelle règle.

Trop de faux positifs

Revenez en DetectionOnly, analysez les patterns, ajustez via exclusions ciblées (par URL ou par règle ID).

Performance dégradée

Désactivez le scan du body pour les gros uploads :

location /upload {
    modsecurity_rules '
        SecRequestBodyAccess Off
    ';
}

Logs trop verbeux

SecAuditLogParts ABCFHZ
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"

Ne log que les requêtes pertinentes.

Commandes utiles

sudo nginx -t                                          # tester config
sudo systemctl reload nginx                            # recharger
sudo tail -f /var/log/modsec_audit.log                 # logs audit
sudo tail -f /var/log/nginx/error.log                  # erreurs nginx
sudo grep "id \"941100\"" /var/log/modsec_audit.log    # tracer une règle

# Updater CRS
cd /etc/nginx/modsec/coreruleset
sudo git pull
sudo systemctl reload nginx

Conclusion

ModSecurity + OWASP CRS bloque la majorité des attaques web automatisées sans modifier votre application. Avantages :

  • Couverture des CVE web courantes
  • Mises à jour gratuites via OWASP
  • Logs détaillés pour analyse
  • Performance acceptable (<15ms)

Pour aller plus loin :

  • Combinez avec Fail2ban pour bloquer durablement les IPs récidivistes
  • Utilisez CrowdSec pour de l'intelligence collaborative
  • Pour du SaaS, considérez aussi NAXSI (alternative plus légère)

Ressources

Rejoignez notre serveur communautaire Discord

Pour toute question, suggestion ou simplement pour discuter avec la communauté, rejoignez-nous sur Discord !

900+Membres