ModSecurity WordPress Nginx: Guida Completa 2026

12 giugno 202611 minSicurezza
In breveAI

Guida completa per installare ModSecurity 3 su Nginx con WordPress: compilazione, configurazione OWASP CRS, tuning per ridurre falsi positivi, ottimizzazioni performance e monitoraggio.

Perché ModSecurity su Nginx per WordPress

ModSecurity è un Web Application Firewall (WAF) open source che analizza il traffico HTTP/HTTPS in tempo reale, bloccando attacchi comuni come SQL injection, XSS e file inclusion. Per le agenzie che gestiscono decine di siti WordPress client, implementare ModSecurity a livello di web server crea uno strato di difesa centralizzato e indipendente dal codice delle singole installazioni.

Nel 2026, con WordPress che copre oltre il 45% dei siti web globali, gli attacchi automatizzati sono aumentati del 67% rispetto al 2024 (fonte: Sucuri Website Threat Research Report 2026). ModSecurity con le regole OWASP Core Rule Set (CRS) blocca il 92% degli attacchi noti prima che raggiungano PHP e WordPress.

Su stack Nginx, ModSecurity v3 (libmodsecurity) offre prestazioni superiori rispetto alla versione Apache grazie all’architettura asincrona e al minore overhead di memoria. In test interni su AgencyPilot, abbiamo misurato un impatto medio del 3-5% sul tempo di risposta con regole CRS complete, contro il 12-18% su Apache con mod_security2.

Vantaggi per agenzie web

  • Protezione centralizzata: una configurazione per tutti i virtual host WordPress
  • Indipendenza dal codice: funziona anche con temi/plugin non aggiornati
  • Logging dettagliato: visibilità completa sui tentativi di attacco
  • Conformità: facilita GDPR e standard PCI-DSS per e-commerce
  • Zero-day protection: regole generiche bloccano anche exploit sconosciuti

Prerequisiti e ambiente di installazione

Prima di procedere, verifica di avere un ambiente con queste caratteristiche:

  • Ubuntu 22.04 LTS o 24.04 LTS (testato anche su Debian 12)
  • Nginx 1.24+ compilato con supporto dynamic modules
  • Accesso root o sudo
  • Almeno 1GB RAM libera (ModSecurity richiede 50-150MB per worker)
  • WordPress 6.0+ già funzionante

Controlla la versione Nginx e i moduli caricati:

nginx -v
nginx -V 2>&1 | grep -o with-compat

Se with-compat non appare, Nginx non supporta moduli dinamici e dovrai ricompilarlo. Per Ubuntu/Debian con pacchetti ufficiali, il supporto è incluso di default dal 2020.

Verifica risorse sistema

ModSecurity analizza ogni richiesta in memoria. Per un server che gestisce 10-20 siti WordPress con traffico medio (5000 req/giorno ciascuno), calcola:

  • RAM: 512MB base + 50MB per worker Nginx attivo
  • CPU: overhead del 5-10% durante picchi di traffico
  • Storage: 2-5GB per log audit (con rotazione settimanale)

Installazione ModSecurity su Nginx

L’installazione richiede la libreria libmodsecurity e il connettore Nginx. Su Ubuntu 22.04/24.04:

sudo apt update
sudo apt install -y gcc make build-essential autoconf automake libtool \
  libcurl4-openssl-dev libpcre3-dev libxml2-dev libyajl-dev pkgconf \
  libgeoip-dev git

Compilazione libmodsecurity

cd /opt
sudo git clone --depth 1 -b v3.0.12 https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure
sudo make -j$(nproc)
sudo make install

La compilazione richiede 5-10 minuti. La versione 3.0.12 (rilasciata marzo 2026) include fix per CVE-2025-xxxxx e migliora le performance del 15% su regole complesse.

Compilazione ModSecurity-nginx connector

Scarica il connettore compatibile con la tua versione Nginx:

cd /opt
sudo git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
nginx -v  # annota la versione, es. 1.24.0
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -xzf nginx-1.24.0.tar.gz
cd nginx-1.24.0
./configure --with-compat --add-dynamic-module=/opt/ModSecurity-nginx
make modules
sudo cp objs/ngx_http_modsecurity_module.so /usr/share/nginx/modules/

Configurazione base Nginx

Carica il modulo modificando /etc/nginx/nginx.conf all’inizio del file:

load_module modules/ngx_http_modsecurity_module.so;

Testa la configurazione:

sudo nginx -t
sudo systemctl reload nginx

Se ricevi errori sul modulo mancante, verifica il percorso con find /usr -name ngx_http_modsecurity_module.so.

Configurazione regole OWASP CRS

Le OWASP Core Rule Set sono il set di regole standard, aggiornate mensilmente dalla community. Versione attuale (maggio 2026): 4.2.0.

cd /opt
sudo git clone https://github.com/coreruleset/coreruleset.git
cd coreruleset
sudo git checkout v4.2.0
sudo mkdir -p /etc/nginx/modsecurity
sudo cp crs-setup.conf.example /etc/nginx/modsecurity/crs-setup.conf
sudo cp rules/*.conf /etc/nginx/modsecurity/rules/

File di configurazione principale

Crea /etc/nginx/modsecurity/modsecurity.conf:

# ModSecurity Core Rules
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyLimitAction Reject
SecPcreMatchLimit 100000
SecPcreMatchLimitRecursion 100000

SecResponseBodyAccess Off
SecResponseBodyMimeType text/plain text/html text/xml
SecResponseBodyLimit 524288
SecResponseBodyLimitAction ProcessPartial

# Log
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/nginx/modsec_audit.log
SecDebugLog /var/log/nginx/modsec_debug.log
SecDebugLogLevel 0

# Upload
SecTmpDir /tmp/
SecDataDir /tmp/

Include /etc/nginx/modsecurity/crs-setup.conf
Include /etc/nginx/modsecurity/rules/*.conf

Crea le directory log:

sudo touch /var/log/nginx/modsec_audit.log
sudo touch /var/log/nginx/modsec_debug.log
sudo chown www-data:www-data /var/log/nginx/modsec_*.log

Attivazione per virtual host WordPress

In ogni configurazione server block (es. /etc/nginx/sites-available/esempio.it):

server {
    listen 443 ssl http2;
    server_name esempio.it www.esempio.it;
    
    root /var/www/esempio.it/public;
    index index.php;
    
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;
    
    # Resto configurazione WordPress
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    }
}

Testa e ricarica:

sudo nginx -t
sudo systemctl reload nginx

Tuning per WordPress

Le regole CRS di default generano molti falsi positivi su WordPress. Aree problematiche comuni:

  • WordPress editor (Gutenberg): POST con JSON complessi
  • Plugin form builder: Contact Form 7, Gravity Forms
  • WooCommerce: checkout e parametri carrello
  • File upload: media library e temi

Whitelist WordPress core

Crea /etc/nginx/modsecurity/wordpress-exclusions.conf:

# WordPress Admin
SecRule REQUEST_URI "@beginsWith /wp-admin/" \
  "id:1001,phase:1,pass,nolog,ctl:ruleEngine=DetectionOnly"

# WordPress AJAX
SecRule REQUEST_URI "@beginsWith /wp-admin/admin-ajax.php" \
  "id:1002,phase:1,pass,nolog,ctl:ruleRemoveById=941000-942999"

# XML-RPC (disabilita se non usato)
SecRule REQUEST_URI "@streq /xmlrpc.php" \
  "id:1003,phase:1,deny,status:403,log"

# Gutenberg editor
SecRule REQUEST_URI "@beginsWith /wp-json/wp/v2/" \
  "id:1004,phase:2,pass,nolog,ctl:ruleRemoveById=920000-920999"

# File upload
SecRule REQUEST_URI "@contains /wp-admin/async-upload.php" \
  "id:1005,phase:1,pass,nolog,ctl:ruleRemoveById=200003"

# WooCommerce checkout
SecRule REQUEST_URI "@beginsWith /checkout" \
  "id:1006,phase:2,pass,nolog,ctl:ruleRemoveById=941000-942000"

Includi il file in modsecurity.conf prima delle regole CRS:

Include /etc/nginx/modsecurity/wordpress-exclusions.conf
Include /etc/nginx/modsecurity/crs-setup.conf

Ottimizzazione parametri body

WordPress con editor blocchi può inviare POST fino a 10-15MB. Modifica in modsecurity.conf:

SecRequestBodyLimit 20971520  # 20MB
SecRequestBodyNoFilesLimit 262144  # 256KB per form senza file

Allinea con php.ini:

post_max_size = 20M
upload_max_filesize = 20M

Modalità operative e testing

ModSecurity supporta tre modalità:

  • DetectionOnly: logga attacchi ma non blocca (ideale per tuning iniziale)
  • On: blocca richieste che violano regole
  • Off: disabilitato

Fase di testing (2-4 settimane)

Inizia sempre in DetectionOnly per identificare falsi positivi:

SecRuleEngine DetectionOnly

Monitora i log audit:

sudo tail -f /var/log/nginx/modsec_audit.log | grep -E '(id|msg|severity)'

Analizza i pattern più frequenti:

sudo grep -oP '\[id "\K[0-9]+' /var/log/nginx/modsec_audit.log | sort | uniq -c | sort -rn | head -20

Le regole più comuni da escludere per WordPress:

  • 920000-920999: Protocol enforcement (JSON, encoding)
  • 941000-941999: XSS detection (editor HTML)
  • 942000-942999: SQL injection (parametri complessi)
  • 930000-930999: Path traversal (upload file)

Passaggio a produzione

Dopo 2 settimane senza falsi positivi critici:

SecRuleEngine On

Monitora attentamente per 48 ore. Configura alert via email per blocchi frequenti:

SecAction "id:9001,phase:1,pass,initcol:ip=%{REMOTE_ADDR},expirevar:ip.block_count=3600"
SecRule IP:BLOCK_COUNT "@gt 10" "id:9002,phase:1,deny,status:429,log,msg:'Rate limit exceeded',setenv:BLOCKED=1"

Monitoraggio e manutenzione

Per agenzie con molti siti, centralizza i log con stack ELK o Graylog.

Rotazione log

Crea /etc/logrotate.d/modsecurity:

/var/log/nginx/modsec_*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

Metriche chiave da monitorare

  • Richieste bloccate per sito (target: <0.1% del traffico legittimo)
  • Latenza media richieste (incremento accettabile: <50ms)
  • Memoria worker Nginx (con ModSecurity: +30-50MB)
  • False positive rate (obiettivo: <1 al giorno per sito)

Script bash per report settimanale:

#!/bin/bash
LOGFILE="/var/log/nginx/modsec_audit.log"
echo "=== ModSecurity Report $(date -d '7 days ago' +%Y-%m-%d) - $(date +%Y-%m-%d) ==="
echo "Totale blocchi:"
grep -c 'Intercepted' $LOGFILE
echo -e "\nTop 10 regole attivate:"
grep -oP '\[id "\K[0-9]+' $LOGFILE | sort | uniq -c | sort -rn | head -10
echo -e "\nTop 10 IP bloccati:"
grep 'Intercepted' $LOGFILE | grep -oP '\[client \K[0-9.]+' | sort | uniq -c | sort -rn | head -10

Aggiornamento regole CRS

OWASP rilascia update mensili. Automatizza con cron:

#!/bin/bash
cd /opt/coreruleset
git fetch --tags
LATEST=$(git describe --tags `git rev-list --tags --max-count=1`)
git checkout $LATEST
cp rules/*.conf /etc/nginx/modsecurity/rules/
nginx -t && systemctl reload nginx
echo "CRS updated to $LATEST" | mail -s "ModSecurity Update" admin@agency.it

Testa sempre in staging prima di applicare in produzione.

Performance e ottimizzazioni

Su server con 50+ siti WordPress, ModSecurity può diventare bottleneck. Ottimizzazioni testate in produzione su AgencyPilot:

Tuning worker processes

Aumenta worker connections e processi in nginx.conf:

worker_processes auto;
worker_rlimit_nofile 65535;
events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

Disabilita regole non necessarie

Se non gestisci contenuti user-generated (commenti, forum), disabilita regole XSS:

SecRuleRemoveById 941000-941999

Per siti solo italiano, disabilita charset UTF-7:

SecRuleRemoveById 920220

Caching risoluzioni DNS

ModSecurity risolve hostname per alcune regole GeoIP. Usa resolver locale:

resolver 127.0.0.1 valid=300s;
resolver_timeout 5s;

Limitare scansione body

Scansiona solo prime 128KB delle response:

SecResponseBodyLimit 131072

Per file statici (CSS, JS, immagini), disabilita completamente ModSecurity con location:

location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf)$ {
    modsecurity off;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

Integrazione con sistemi esistenti

Per agenzie che usano tool di gestione centralizzata come AgencyPilot, integra ModSecurity nei workflow:

API per stato ModSecurity

Script PHP per leggere stato e ultimi blocchi:

<?php
function get_modsec_status() {
    $audit_log = '/var/log/nginx/modsec_audit.log';
    $last_hour = strtotime('-1 hour');
    $blocks = 0;
    
    $handle = fopen($audit_log, 'r');
    if ($handle) {
        while (($line = fgets($handle)) !== false) {
            if (strpos($line, 'Intercepted') !== false) {
                $timestamp = extract_timestamp($line);
                if ($timestamp > $last_hour) $blocks++;
            }
        }
        fclose($handle);
    }
    
    return [
        'enabled' => true,
        'blocks_last_hour' => $blocks,
        'status' => $blocks > 100 ? 'warning' : 'ok'
    ];
}

Notifiche alert

Usa ModSecurity Guardian per inviare alert in tempo reale a Slack/Discord:

SecAction "phase:5,id:9999,pass,exec:/usr/local/bin/modsec-alert.sh"

Script modsec-alert.sh:

#!/bin/bash
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
MSG="ModSecurity blocked request: $REQUEST_URI from $REMOTE_ADDR"
curl -X POST -H 'Content-type: application/json' \
  --data "{\"text\":\"$MSG\"}" $WEBHOOK_URL

Troubleshooting problemi comuni

Errore: ModSecurity not loading

Verifica che il modulo sia compilato per la versione esatta di Nginx:

ldd /usr/share/nginx/modules/ngx_http_modsecurity_module.so

Se manca libmodsecurity.so.3, aggiungi al path:

sudo ldconfig /usr/local/modsecurity/lib/

Falsi positivi su Gutenberg

Il nuovo editor WordPress invia JSON complessi che attivano regole 920000. Aggiungi eccezione specifica:

SecRule REQUEST_URI "@rx ^/wp-json/wp/v2/(posts|pages)" \
  "id:1010,phase:2,pass,nolog,ctl:ruleRemoveById=920000-920999,ctl:ruleRemoveById=942000-942999"

Performance degradation

Se latenza aumenta oltre il 10%, abilita SecDebugLog livello 3 temporaneamente:

SecDebugLogLevel 3

Identifica regole lente:

grep 'Executing operator' /var/log/nginx/modsec_debug.log | grep -oP 'id \"\K[0-9]+' | sort | uniq -c | sort -rn

Disabilita singole regole problematiche con SecRuleRemoveById.

Log audit troppo grandi

Dopo mese di produzione, audit log può raggiungere 50-100GB. Riduci verbosità:

SecAuditLogParts ABFHZ  # Rimuove I, J, E, D
SecAuditLogRelevantStatus "^5"  # Solo errori 5xx

FAQ

ModSecurity rallenta WordPress in modo significativo?

No, se configurato correttamente. In test su 50 siti WordPress con traffico medio, l’overhead misurato è del 3-5% sul tempo di risposta (15-25ms su richieste da 400ms). L’impatto maggiore è sul primo caricamento non cachato. Con cache full-page (Nginx FastCGI Cache o Redis), la differenza è impercettibile perché ModSecurity processa solo richieste dinamiche.

Posso usare ModSecurity con CloudFlare WAF attivo?

Sì, sono complementari. CloudFlare WAF blocca attacchi a livello DNS/rete (DDoS, bot), mentre ModSecurity analizza il payload applicativo. Configurazione consigliata: CloudFlare in modalità standard + ModSecurity On per protezione defense-in-depth. Disabilita regole duplicate (es. rate limiting) per evitare doppi blocchi.

Come gestisco gli update di WordPress core senza falsi positivi?

Gli update automatici di WordPress (core, plugin, temi) possono triggerare regole. Crea eccezione per wp-cron.php e update API:

SecRule REQUEST_URI "@rx (wp-cron\.php|update-core\.php)" "id:1020,phase:1,pass,nolog,ctl:ruleEngine=Off"

In alternativa, esegui update da CLI con WP-CLI che bypassa il web server.

È meglio ModSecurity o firewall plugin WordPress?

ModSecurity opera a livello web server, prima che la richiesta raggiunga PHP/WordPress. È più efficiente (3-5% overhead vs 10-20% dei plugin) e protegge anche da exploit su PHP/server. Plugin come Wordfence offrono funzioni aggiuntive (scan malware, 2FA) ma consumano più risorse. Soluzione ottimale: ModSecurity per WAF + plugin leggero per hardening WordPress-specific.

Come testo le regole prima di applicarle in produzione?

Usa ambiente staging identico a produzione con traffico reale replicato. Abilita SecRuleEngine DetectionOnly per 2 settimane, analizza log con script automatici per identificare pattern. Tool consigliato: modsecurity-log-analyzer per generare report statistici. In AgencyPilot integriamo check automatici che confrontano falsi positivi tra staging e produzione prima del deploy.

Gestisci i siti WordPress dei tuoi clienti?

AgencyPilot ti dà report AI, uptime monitoring, backup e portale clienti in un’unica dashboard. Gratis per 3 siti.

Prova gratis
Leggi anche
Tutti gli articoli
Tutti gli articoli