«Ma avevamo il firewall». È una frase che sentiamo spesso all’inizio di una bonifica, e quasi sempre è vera: il sito era dietro Cloudflare, o aveva Wordfence attivo, o il server aveva ModSecurity. Il firewall applicativo, o WAF, faceva il suo lavoro. Il problema è che quel lavoro copre una parte precisa degli attacchi, e l’infezione è passata da un’altra parte: una password rubata, un’origine raggiungibile senza passare dal filtro, una backdoor installata prima che il WAF venisse attivato.
Un WAF filtra richieste HTTP. Tutto quello che non è una richiesta HTTP sospetta, come un accesso con credenziali valide, un cron job o un file già presente sul disco, per il WAF semplicemente non esiste.
In questo articolo mettiamo a confronto le tre famiglie di WAF che si incontrano sui siti WordPress, cosa bloccano davvero e cosa non possono vedere, e soprattutto i rischi che un WAF introduce se configurato male: l’origine scoperta, l’indirizzo IP dei visitatori falsificabile, i falsi positivi, il traffico cifrato consegnato a un terzo.
Tre famiglie di WAF, tre punti diversi del percorso
Una richiesta verso un sito WordPress attraversa diversi livelli prima di arrivare al codice del plugin che la gestisce, e un WAF può stare in ciascuno di essi. La posizione determina cosa vede e cosa può fare.
Il WAF cloud è un reverse proxy davanti al sito: il DNS del dominio punta ai server del fornitore, che terminano la connessione TLS, analizzano la richiesta e la inoltrano al server di origine. È il modello di Cloudflare e del Sucuri Website Firewall, che nella sua documentazione elenca protezione da SQL injection, XSS ed esecuzione remota di codice, virtual patching, mitigazione DDoS, blocco di bot e scanner e funzioni di cache e CDN. Cloudflare offre il suo Free Managed Ruleset su tutti i piani, mentre il Cloudflare Managed Ruleset e la sua versione dell’OWASP Core Ruleset sono riservati ai piani a pagamento. Il vantaggio del modello cloud è che il traffico ostile, compresi gli attacchi volumetrici, si ferma prima di toccare il server.
Il WAF di server è un modulo del web server, e il caso tipico è ModSecurity con l’OWASP Core Rule Set (CRS), un insieme di regole libere che riconoscono le famiglie di attacco più comuni. Il repository di ModSecurity è oggi ospitato nell’organizzazione OWASP su GitHub, con la versione 2 per Apache e la libreria della versione 3 usata con NGINX. Vede la richiesta già decifrata sul server che si amministra, senza terze parti, ma non ferma nulla che non sia già arrivato fin lì.
Il WAF applicativo gira dentro PHP. Il caso più diffuso è il firewall di Wordfence, che la pagina del plugin definisce un endpoint firewall: nella modalità estesa si carica prima di WordPress tramite la direttiva auto_prepend_file di PHP. Conosce il contesto dell’applicazione, per esempio se l’utente è autenticato, ma consuma risorse PHP del sito e, come ricorda la stessa pagina, nella versione gratuita riceve le nuove regole con 30 giorni di ritardo rispetto a quella a pagamento.
Cosa bloccano davvero
Il punto di forza di un WAF sono gli attacchi riconoscibili dalla forma della richiesta. Gli exploit noti delle vulnerabilità dei plugin, che arrivano a migliaia di siti dagli stessi scanner automatici, hanno parametri, percorsi e payload ricorrenti. Una regola scritta dopo la pubblicazione della vulnerabilità li ferma anche sui siti che non hanno ancora aggiornato: è il virtual patching, di cui abbiamo parlato nell’articolo sulle vulnerabilità 0-day dei plugin, ed è il servizio più prezioso che un WAF possa rendere nei giorni tra l’annuncio di una falla e l’aggiornamento.
Poi ci sono il traffico automatico e il volume. Un WAF blocca scanner e bot noti, limita la frequenza delle richieste verso wp-login.php e xmlrpc.php, presenta una verifica ai client sospetti. I WAF cloud assorbono anche gli attacchi DDoS, che un modulo sul server o un plugin non possono contrastare: quando la richiesta arriva a PHP, la banda e le connessioni sono già state consumate. Infine le regole generiche del CRS riconoscono SQL injection, XSS o inclusioni di file anche in vulnerabilità mai viste, con un tasso di successo variabile e il prezzo dei falsi positivi di cui parleremo più avanti.
Cosa non possono vedere
La lista dei limiti è più importante di quella dei pregi, perché è lì che nascono le infezioni «nonostante il firewall». Un WAF non distingue un amministratore legittimo da un attaccante che usa la sua password: le richieste sono identiche. Le credenziali rubate da un PC infetto, uno scenario che descriviamo nell’articolo sulle credenziali FTP rubate, bypassano qualunque WAF, e se l’accesso avviene via SFTP o SSH non passa nemmeno dal web. La difesa, in questo caso, è l’autenticazione a due fattori.
Un WAF non vede nemmeno il malware già presente. Se la backdoor era sul disco prima dell’attivazione del filtro, continua a funzionare: può rispondere solo a richieste dall’aspetto innocuo, oppure non ricevere affatto richieste, come i cron job che riscaricano il codice ogni notte o i processi PHP che restano in memoria. Il firewall di Wordfence è affiancato da uno scanner di file, ma lo scanner è un altro strumento, con i limiti che abbiamo descritto. Infine la logica applicativa: il card testing su WooCommerce usa richieste di checkout perfettamente valide, e un WAF può solo rallentarlo con limiti di frequenza e verifiche anti-bot.
Il rischio numero uno: l’origine raggiungibile
Un WAF cloud protegge solo il traffico che passa da lui. Se l’indirizzo IP del server di origine è noto e il server accetta connessioni da chiunque, un attaccante può indirizzare le richieste direttamente all’origine, e il WAF diventa decorativo. Scoprire quell’indirizzo è spesso facile: gli archivi storici dei DNS conservano i record di prima dell’attivazione del proxy, i record MX e SPF possono puntare allo stesso server, un sottodominio non protetto come ftp. o cpanel. lo rivela, un pingback XML-RPC o un’email inviata dal sito lo espongono nelle connessioni in uscita. Di sottodomini dimenticati parliamo anche nell’articolo sul DNS hijacking e il takeover dei sottodomini.
Verificare se la propria origine è esposta richiede un comando: si chiede la pagina all’indirizzo del server, forzando la risoluzione del nome, da una rete qualunque. Se risponde il sito, l’origine è raggiungibile.
# 203.0.113.10 è l'IP del server di origine: se il sito risponde, il WAF si può aggirare
curl -skI --resolve www.esempio.it:443:203.0.113.10 https://www.esempio.it/ | head -3
La correzione è accettare connessioni HTTP e HTTPS solo dagli indirizzi del fornitore. Cloudflare pubblica i suoi intervalli in cloudflare.com/ips, anche in formato testo; Sucuri dedica una pagina alla prevenzione del bypass del firewall e fornisce l’elenco dal pannello. Il posto giusto per il filtro è il firewall di sistema, non il web server: con il modulo realip attivo, come vedremo tra poco, le direttive allow e deny di NGINX valutano l’IP del visitatore e non quello del proxy.
# nftables: porte 80 e 443 aperte solo agli intervalli di Cloudflare
nft add table inet waf
nft add set inet waf cf4 '{ type ipv4_addr; flags interval; }'
nft add set inet waf cf6 '{ type ipv6_addr; flags interval; }'
nft add element inet waf cf4 "{ $(curl -s https://www.cloudflare.com/ips-v4/ | paste -sd, -) }"
nft add element inet waf cf6 "{ $(curl -s https://www.cloudflare.com/ips-v6/ | paste -sd, -) }"
nft add chain inet waf input '{ type filter hook input priority 0; policy accept; }'
nft add rule inet waf input tcp dport '{ 80, 443 }' ip saddr != @cf4 drop
nft add rule inet waf input tcp dport '{ 80, 443 }' ip6 saddr != @cf6 drop
Gli intervalli cambiano di rado, ma cambiano: lo script va rieseguito periodicamente, e prima delle regole di blocco conviene aggiungere le eccezioni per il monitoraggio e per gli indirizzi degli amministratori. Cloudflare aggiunge un livello più robusto, le Authenticated Origin Pulls: il proxy presenta un certificato client TLS e l’origine accetta solo connessioni che lo mostrano. Esiste un certificato globale condiviso tra tutti gli account e uno per zona caricato dal cliente; solo il secondo garantisce che la richiesta arrivi dalla propria configurazione Cloudflare e non da quella di chiunque altro.
# NGINX, blocco server del sito: solo connessioni con il certificato client atteso
ssl_client_certificate /etc/nginx/certs/origin-pull-ca.pem;
ssl_verify_client on;
Se l’indirizzo dell’origine è stato esposto per anni prima dell’attivazione del WAF, cambiarlo durante la migrazione è la scelta più pulita: i vecchi record DNS non porteranno più da nessuna parte.
L’IP reale del visitatore e le intestazioni falsificabili
Dietro un proxy il server vede come client l’indirizzo del proxy, e l’IP del visitatore arriva in un’intestazione HTTP: CF-Connecting-IP per Cloudflare, X-Sucuri-ClientIP per Sucuri, X-Forwarded-For in generale. Le intestazioni però le scrive chiunque. Secondo la documentazione di Cloudflare, se la richiesta arriva già con un X-Forwarded-For, Cloudflare vi aggiunge un indirizzo invece di sostituirlo: il primo valore della lista può quindi essere stato scelto dall’attaccante.
La regola è fidarsi dell’intestazione solo quando la connessione arriva da un indirizzo del proxy. In NGINX lo fa il modulo realip, con l’elenco degli intervalli in set_real_ip_from, come indica la guida di Cloudflare al ripristino degli IP; in Apache lo fa mod_remoteip con RemoteIPTrustedProxy. Un frammento PHP che copia l’intestazione in REMOTE_ADDR senza controllare la provenienza, come quello proposto nella documentazione di Sucuri, è sicuro solo se l’origine accetta connessioni esclusivamente dal firewall.
# Genera /etc/nginx/conf.d/cloudflare-realip.conf dagli intervalli ufficiali
{
for rete in $(curl -s https://www.cloudflare.com/ips-v4/) $(curl -s https://www.cloudflare.com/ips-v6/); do
echo "set_real_ip_from $rete;"
done
echo "real_ip_header CF-Connecting-IP;"
} > /etc/nginx/conf.d/cloudflare-realip.conf
nginx -t && systemctl reload nginx
Sbagliare in un senso o nell’altro ha conseguenze concrete. Se il server non ripristina l’IP, i log di accesso mostrano solo indirizzi del proxy e un’analisi forense diventa quasi impossibile. Se lo ripristina fidandosi di chiunque, un attaccante può cambiare IP a ogni richiesta, aggirare i limiti sui tentativi di login e farsi registrare con l’indirizzo di qualcun altro. Anche i plugin di sicurezza hanno un’impostazione per scegliere da quale intestazione leggere l’IP, e va allineata alla configurazione reale.
Falsi positivi: quando il WAF rompe il checkout
Un WAF che blocca tutto ciò che somiglia a un attacco blocca anche parecchio traffico legittimo. L’editor a blocchi salva HTML e JavaScript tramite l’API REST, che a una regola anti-XSS sembrano un’iniezione; i costruttori di pagine inviano strutture enormi e annidate; i webhook dei gateway di pagamento arrivano da indirizzi e con corpi insoliti. Il sintomo tipico è un errore 403 al salvataggio di un articolo o, peggio, un checkout che fallisce in modo intermittente senza che nessuno se ne accorga subito.
Il CRS gestisce il compromesso con i livelli di paranoia: al livello 1 i falsi positivi sono pochi, ai livelli superiori le regole diventano più aggressive e i falsi positivi, per stessa ammissione della documentazione, sono attesi. Per WordPress esiste un plugin di esclusioni ufficiale che copre il core, ma non i costruttori di pagine e i plugin di terze parti, che vanno regolati a mano. Il metodo è sempre lo stesso: partire in sola rilevazione, leggere cosa verrebbe bloccato e scrivere eccezioni mirate su singole regole e singoli parametri, mai disattivare il WAF su interi percorsi come /wp-admin/.
# ModSecurity: prima settimana in sola rilevazione
SecRuleEngine DetectionOnly
# Quali regole scatterebbero più spesso (log di errore di Apache)
grep -o '\[id "[0-9]*"\]' /var/log/apache2/error.log | sort | uniq -c | sort -rn | head
# Eccezione mirata: una regola, un parametro, un percorso
SecRule REQUEST_FILENAME "@endsWith /wp-admin/post.php" \
"id:1000100,phase:1,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content"
Sui WAF cloud il principio non cambia: i fornitori offrono una modalità di solo registro per le regole gestite e la possibilità di escludere singole regole su percorsi specifici. Dopo ogni modifica, un acquisto di prova completo e il salvataggio di un articolo con l’editor sono il test minimo.
TLS a un terzo e protezione dei dati
Per ispezionare le richieste, un WAF cloud deve decifrarle. Significa che password di accesso, dati dei moduli di contatto, indirizzi e ordini dei clienti transitano in chiaro sui server del fornitore, prima di essere cifrati di nuovo verso l’origine. Per il GDPR il fornitore diventa un responsabile del trattamento, e servono un accordo ai sensi dell’articolo 28, l’indicazione nel registro dei trattamenti e, se i dati escono dall’Unione Europea, una base per il trasferimento. I grandi fornitori pubblicano accordi standard: quello di Cloudflare, per esempio, è il Data Processing Addendum, che richiama le clausole contrattuali standard e il Data Privacy Framework.
Non è un motivo per rinunciare al WAF cloud, ma è una scelta da fare consapevolmente e da documentare, anche perché in caso di incidente la mappa dei soggetti che trattano i dati serve subito, come spieghiamo nell’articolo su sito hackerato e data breach. Il segmento tra proxy e origine va cifrato anch’esso, con la modalità «Full (strict)» o equivalente: un proxy che parla in chiaro con l’origine annulla metà del senso di HTTPS. Chi non vuole terze parti nel percorso ha nel WAF di server l’alternativa naturale, rinunciando però alla mitigazione dei DDoS.
Un livello, non la sicurezza
Il rischio più sottile del WAF è psicologico: la sensazione di essere protetti fa rimandare gli aggiornamenti, tollerare plugin abbandonati, trascurare le password. Un WAF compra tempo tra la pubblicazione di una vulnerabilità e la patch, e riduce il rumore di fondo degli attacchi automatici. Non sostituisce l’aggiornamento, che resta la difesa principale, né la sorveglianza delle vulnerabilità dei plugin installati, di cui parliamo nell’articolo sui bollettini di sicurezza.
E soprattutto non ripulisce un sito già compromesso. Attivare un WAF su un sito infetto blocca forse il prossimo attacco, ma lascia al loro posto le backdoor, gli amministratori aggiunti e i cron che l’attaccante ha già installato. Se il tuo sito continua a mostrare segni di infezione nonostante il firewall, scrivici: interveniamo sui file, sul database e sul sistema, compresi cron e processi in memoria, con una pulizia garantita in 6, 12 o 24 ore per ogni installazione WordPress, e verifichiamo anche che la configurazione del WAF non lasci l’origine scoperta.