Tutti gli articoli
Hardening10 min di letturaTeam WPsec.it

WordPress sotto attacco DDoS a livello applicativo (L7): cosa fare nelle prime due ore

Flood HTTP su xmlrpc, wp-login e ricerca interna: come riconoscerlo, cosa fare sul sito e cosa sul server nelle prime due ore, e perché bloccare gli IP non basta.

Condividi
WordPress sotto attacco DDoS a livello applicativo (L7): cosa fare nelle prime due ore

Un attacco DDoS applicativo, o Layer 7, non satura la banda: satura WordPress. Ogni richiesta arriva a PHP, apre una connessione a MySQL e occupa un worker per qualche centinaio di millisecondi. Ne bastano poche decine al secondo, distribuite su qualche migliaio di IP, per mandare in coda un server che per il provider "è raggiungibile". Questa guida copre le prime due ore: riconoscere l'attacco, dividere il lavoro tra sito e server, non sprecare tempo su contromisure che non abbassano le richieste.

Come si distingue un flood L7 da un picco di traffico vero?

Non dal carico, che sale in entrambi i casi, ma dalla forma delle richieste. Un picco legittimo (una newsletter, un passaggio in TV) ha un referrer coerente, colpisce le pagine effettivamente linkate, e ogni pagina si porta dietro CSS, JavaScript e immagini. Un flood chiede solo l'endpoint che costa di più, e lo chiede sempre uguale.

Tre comandi sul log degli accessi bastano per decidere. Il percorso cambia con il pannello (/var/log/apache2/, /var/log/nginx/, /usr/local/apache/domlogs/ su cPanel):

# 1. Quali URL vengono chiesti di più negli ultimi 50.000 accessi
tail -n 50000 access.log | awk '{print $7}' | cut -d'?' -f1 | sort | uniq -c | sort -rn | head -15

# 2. Quanti IP distinti e quanto pesa il primo
tail -n 50000 access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -5
tail -n 50000 access.log | awk '{print $1}' | sort -u | wc -l

# 3. Quali user agent, e quanti diversi
tail -n 50000 access.log | awk -F'"' '{print $6}' | sort | uniq -c | sort -rn | head -10

I segnali che confermano il flood:

  • gli URL in testa sono sempre gli stessi e tutti dinamici: xmlrpc.php, wp-login.php, /?s=qualcosa, admin-ajax.php, oppure archivi con parametri di filtro (?orderby=, ?filter_colore=, ?min_price=) che la cache non può servire;
  • nessun IP domina: il primo pesa meno dell'1 percento e i distinti sono migliaia, spesso di reti residenziali o di proxy;
  • user agent che ruotano: versioni di Chrome vecchie di anni, stringhe vuote, decine di combinazioni diverse;
  • rapporto pagine/asset sballato: migliaia di richieste HTML e quasi nessuna a /wp-content/ o /wp-includes/;
  • carico alto con MySQL quasi a riposo: uptime mostra un load ben sopra il numero di core, ps -eo comm | grep -c php-fpm (o lsphp su LiteSpeed) è al massimo configurato, mentre mysqladmin processlist mostra poche query e molte connessioni in Sleep.

Se invece i primi URL sono pagine reali con asset al seguito e Analytics vede sessioni umane, è un picco di traffico: il problema è la capacità, e vale il percorso della diagnosi delle performance.

Perché bloccare gli IP uno per uno non funziona?

Tre motivi:

  1. Gli IP ruotano più in fretta di te. Una botnet o una rete di proxy residenziali usa ogni indirizzo per qualche decina di richieste e lo abbandona. Quando il tuo csf -d entra in vigore, quell'IP ha già finito.
  2. Il blocco arriva troppo tardi nella catena. Se lo applica un plugin di sicurezza, la richiesta ha già avviato PHP, caricato WordPress e aperto la connessione al database: hai pagato il costo intero per poi dire "no". È il limite strutturale dei plugin di sicurezza.
  3. La lista cresce e il risultato no. Mille IP in blacklist non sono mille richieste in meno se il conteggio al minuto resta quello.

Il criterio operativo è uno: se dopo cinque minuti di blocchi il numero di richieste al minuto non scende, smetti di bloccare IP e passa alla firma. Il conteggio si legge così:

# richieste al minuto negli ultimi 10 minuti
tail -n 100000 access.log | awk '{print substr($4,2,17)}' | uniq -c | tail -10

Cosa si fa sul sito nelle prime due ore?

Spettano a chi gestisce WordPress. Da soli non fermano un flood serio, ma riducono il costo di ogni richiesta e chiudono gli endpoint colpiti più spesso.

  • Disattivare xmlrpc.php. Quasi nessun sito lo usa. Il blocco va fatto prima di PHP: su Apache in .htaccess con <Files xmlrpc.php>Require all denied</Files>, su nginx con location = /xmlrpc.php { return 403; }. Il filtro add_filter('xmlrpc_enabled', '__return_false') non basta: WordPress viene comunque caricato per rispondere di no.
  • Proteggere wp-login.php. Rate limit per IP sulle POST (con Cloudflare, fail2ban o il modulo del web server), challenge sulle GET se il sito è dietro un proxy, registrazione disattivata se non serve.
  • Servire tutto dalla cache pagina. Un flood su URL cacheabili muore contro la cache. Il trucco degli attaccanti è aggiungere parametri casuali (/?xyz=123) per forzare il miss: la cache va configurata per ignorare i parametri sconosciuti (vedi gli errori comuni di caching).
  • Spegnere la ricerca interna se è lei il bersaglio. /?s= non è cacheabile e fa una query LIKE su tutto il contenuto. Per la durata dell'attacco si risponde 403 a ogni richiesta con s= nella query string, a livello di web server.
  • Chiudere i filtri di archivio abusati. Su WooCommerce le combinazioni di filter_*, orderby e min_price sono infinite per costruzione e un crawler ostile le esplora tutte. Blocco per pattern dei parametri, non per IP.

Questi passi sono anche hardening permanente: la lista completa è nella checklist di hardening WordPress.

Cosa si fa sul server nelle prime due ore?

Qui cambia il mestiere: servono accesso root, conoscenza del web server e un firewall a monte. I principi, in ordine di efficacia:

  1. Negare in fase di accesso, prima di PHP. Una regola deny nel vhost o nella configurazione nginx costa microsecondi e non apre nessun worker. Su Apache SetEnvIf più Require not env, o ModSecurity in modalità blocco; su nginx map più return 444; su LiteSpeed le regole di riscrittura del vhost. Il punto non è lo strumento, è la posizione nella catena.
  2. Bloccare per firma, non per paese. La firma è la combinazione ripetuta: endpoint colpito, forma della query string, user agent, assenza di Accept-Language, versione HTTP. Un blocco per paese fa danni ai clienti veri e non ferma un attaccante con IP nel tuo stesso Paese.
  3. Mettere un WAF davanti. Cloudflare con proxy attivo assorbe il volume prima che tocchi il server: regole WAF sull'endpoint attaccato, rate limiting, managed challenge sulle pagine dinamiche.
  4. Chiudere l'origine. Se l'IP del server è noto (storico DNS, record MX sullo stesso host, sottodomini non proxati), l'attaccante lo colpisce direttamente e Cloudflare non vede nulla. Il firewall cloud del provider (Hetzner Cloud Firewall, i security group di AWS) deve accettare 80 e 443 solo dai range del proxy: a monte, dove nessun firewall host può scavalcarlo. CSF da solo non basta: su molte macchine Imunify360 o le catene nftables di sistema girano prima di lui.
  5. Non riavviare il database. Se MySQL è quasi fermo, riavviarlo fa solo perdere le connessioni buone. Il collo è nei worker PHP: il tuning di pm.max_children stabilizza, ma senza il filtro a monte sposta solo il punto in cui si va in coda.

Sintomo, dove si vede, cosa fare, chi lo fa

SintomoDove si vedeCosa fareChi lo fa
xmlrpc.php in testa al logaccess.log, top URLDeny prima di PHP (.htaccess o location)Sito
POST a raffica su wp-login.phpaccess.log, codice 200 ripetutoRate limit sulle POST, challenge, no registrazioneSito + server
/?s= o parametri di filtro a migliaiaaccess.log, query string403 per pattern di query, cache che ignora i parametriSito + server
Migliaia di IP, nessuno dominanteConteggio per IP con sort e uniq -cSmettere di bloccare IP, blocco per firmaServer
Load alto, MySQL in Sleepuptime, mysqladmin processlistWorker PHP saturi: deny a monte, non restart del DBServer
502, 503, 504 o 508 dal sitoBrowser, log del web serverFiltro in fase di accesso, WAF davanti, cacheServer
Il flood colpisce l'IP direttoLog con host non proxato, Cloudflare non vede trafficoFirewall cloud: 80 e 443 solo dai range del proxyServer
Referrer coerente, asset al seguitoaccess.log, AnalyticsNon è un attacco: capacità e cacheSito

Il provider dice "il server è raggiungibile" e il sito è giù: chi ha ragione?

Tutti e due, ed è per questo che la telefonata finisce male. Il provider guarda ping, SSH e i servizi in esecuzione: un flood L7 li lascia intatti, perché lavora sopra la rete. Il tuo sito invece risponde 503 perché tutti i worker PHP sono occupati, o 508 se sei su hosting condiviso con limiti per account (CloudLinux LVE).

Cosa chiedere, in questo ordine:

  1. il log degli accessi completo delle ultime due ore, non un estratto;
  2. su piano condiviso, se hai toccato i limiti di CPU, memoria o processi;
  3. se il provider può applicare una regola a livello di web server per la firma che gli indichi;
  4. se esiste una protezione a monte (anti-DDoS del datacenter, WAF) e come si attiva.

"Il server è operativo, il problema è il sito" non è una diagnosi: è la descrizione del punto in cui la loro responsabilità finisce. La guida su quando l'hosting non è colpevole spiega come attribuire correttamente.

Chi lo fa sul server se non hai un sistemista?

Il perimetro va detto in chiaro. WPsec.it si occupa del sito: endpoint, cache, regole in .htaccess, hardening di WordPress, e la verifica che il flood non abbia coperto un tentativo di intrusione (un flood è anche un ottimo rumore di fondo per un'intrusione). Il servizio di hardening WordPress e la pagina sulla protezione DDoS per WordPress descrivono cosa facciamo sul sito; i costi sono nella pagina prezzi.

Del server si occupa managedvps.it, il servizio della stessa squadra tecnica dedicato alla macchina Linux: regole di accesso nel web server, firewall host e cloud, WAF a monte, tuning di PHP-FPM e MySQL. Se hai un VPS o un dedicato e nessuno che lo amministri, l'assistenza sul server Linux copre l'intervento sotto attacco, mentre l'hardening del server è il lavoro da fare dopo, per non ripetere le stesse due ore al prossimo flood.

Se sei su hosting condiviso non hai accesso a quel livello: puoi lavorare solo sul sito e chiedere al provider il resto.

Come capisco se il mio sito WordPress è sotto attacco DDoS?

Guarda il log degli accessi, non il carico. Se migliaia di IP diversi chiedono sempre gli stessi endpoint dinamici (xmlrpc.php, wp-login.php, ricerca interna, URL con filtri) senza scaricare CSS e immagini, e il carico è alto con MySQL quasi fermo, è un flood applicativo. Un picco di visite vero ha referrer coerenti e pagine con asset al seguito.

Cloudflare da solo protegge WordPress dagli attacchi DDoS?

Solo se il traffico passa davvero da Cloudflare. Con il proxy attivo, regole WAF e rate limiting assorbono la maggior parte dei flood L7. Ma se l'IP del server è raggiungibile direttamente, l'attaccante lo usa e Cloudflare non vede nulla: il firewall a monte deve accettare 80 e 443 solo dai range di Cloudflare.

Devo bloccare i paesi da cui arriva l'attacco?

Di solito no. Botnet e proxy residenziali sono distribuiti ovunque, incluso il tuo Paese, e un blocco geografico taglia fuori clienti veri senza abbassare le richieste. Blocca per firma: endpoint, forma della query, user agent. Il criterio è misurabile: se il conteggio al minuto non scende, il blocco è sbagliato.

Basta un plugin di sicurezza per fermare un DDoS L7?

No. Un plugin decide dentro PHP, quindi ogni richiesta bloccata ha già consumato un worker e una connessione al database. Il blocco deve avvenire prima di PHP, nel web server o a monte con un WAF. Il plugin resta utile per il login e per il monitoraggio, non come prima linea sotto flood.

Pubblicato il

Condividi

Scritto dal team WPsec.it

Team WPsec.it

Bonifica malware, hardening, performance e manutenzione WordPress.

Prevenzione e gestione

Dopo l'emergenza, o per non arrivarci: le guide sulla gestione.

Sicurezza, velocità e manutenzione di WordPress sono lo stesso lavoro visto da tre lati. Queste pagine spiegano cosa controllare, con quale priorità e quanto costa farlo fare.

Continua a leggere

Articoli correlati.

Plugin nulled WordPress: cosa rischi davvero a usarli
Hardening26 maggio 2026

Plugin nulled WordPress: cosa rischi davvero a usarli

Usare plugin o temi nulled su WordPress espone il sito a backdoor, spam in uscita, blacklist Google, hosting sospeso e perdita di dati WooCommerce. Una guida pratica sui rischi reali e su come uscirne.

9 minTeam WPsec.it