Proteggere un sito Nginx da un attacco applicativo (L7)

Pubblicato il 21/08/2026 Aggiornato il 06/10/2026 50 visualizzazioni
Sécurité VPS Linux Nginx DDoS

Non tutti gli attacchi si somigliano. Un attacco volumetrico mira a saturare il collegamento di rete: è un ingorgo in autostrada, e se ne occupa a monte la protezione By-Hoster, senza che Lei debba fare nulla.

Un attacco applicativo, detto di livello 7, è diverso. Il traffico resta modesto, ma ogni richiesta è costosa: una ricerca, una pagina di accesso, un carrello. Per la rete si tratta di visitatori normali. È solo a livello del Suo server web che la natura del traffico diventa visibile, ed è quindi lì che occorre intervenire.

Come sapere che cosa colpisce realmente il mio server?

Non cambi nulla finché non sa che cosa sta arrivando. Un'impostazione decisa a caso blocca spesso i Suoi veri visitatori senza disturbare l'attaccante.

Gli indirizzi IP più attivi:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Gli URL più richiesti:

awk -F'"' '{print $2}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Il traffico dell'ultimo minuto, per valutarne l'intensità:

tail -n 100000 /var/log/nginx/access.log | awk '{print $4}' | uniq -c | tail -20

Cerca uno schema: una manciata di indirizzi molto loquaci, un singolo URL martellato, uno user agent identico ovunque. È questo schema a dettare la regola, non il contrario.

Verifichi anche che cosa si sta davvero saturando:

uptime
systemctl status php8.3-fpm --no-pager

Spesso non è Nginx a cedere, ma PHP o la base di dati dietro di esso.

Come limitare la frequenza di richieste per indirizzo in Nginx?

Nginx sa contare le richieste per indirizzo e rallentare quelle che superano la soglia. La dichiarazione delle zone avviene nel blocco http (file /etc/nginx/nginx.conf):

http {
    limit_req_zone  $binary_remote_addr zone=req_per_ip:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
}

Poi l'applicazione nel blocco del sito:

server {
    limit_req  zone=req_per_ip burst=20 nodelay;
    limit_conn conn_per_ip 20;
}

Che cosa significa, in concreto:

Impostazione Effetto
rate=10r/s 10 richieste al secondo per indirizzo in regime normale
burst=20 tollera un picco di 20 richieste oltre il ritmo
nodelay serve il picco immediatamente invece di distribuirlo
limit_conn 20 massimo 20 connessioni simultanee per indirizzo

Una zona da 10m memorizza circa 160 000 indirizzi, ampiamente sufficienti.

burst senza nodelay mette le richieste in coda: il sito diventa lento invece di rifiutare. Con nodelay, un visitatore normale che carica una pagina e le sue venti risorse passa senza rallentamenti, mentre un robot che insiste riceve un errore 503.

Protegga più severamente gli URL realmente costosi anziché l'intero sito:

location = /wp-login.php {
    limit_req zone=req_per_ip burst=3 nodelay;
}

Come testare la configurazione Nginx prima di applicarla?

Con nginx -t, che convalida la sintassi senza applicare nulla, poi un ricaricamento a caldo invece di un riavvio.

nginx -t

Questo comando convalida la sintassi senza interrompere nulla. Deve rispondere syntax is ok e poi test is successful. Solo a quel punto:

systemctl reload nginx

reload ricarica la configurazione senza interrompere le connessioni in corso, a differenza di restart. In piena fase di attacco, la differenza conta.

Controlli che cosa viene rifiutato:

grep "limiting requests" /var/log/nginx/error.log | tail -20

Se vede comparire i Suoi stessi indirizzi o quelli dei Suoi clienti, il limite è troppo basso. Lo alzi.

Come servire meno spesso la stessa pagina?

Il modo migliore per assorbire un attacco è spesso non ricalcolare la pagina a ogni richiesta. Una pagina in cache per 60 secondi costa quasi nulla, qualunque sia il numero di richieste.

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=sito:50m inactive=10m;
}
location / {
    proxy_cache sito;
    proxy_cache_valid 200 60s;
    proxy_cache_use_stale error timeout updating;
}

proxy_cache_use_stale è la riga che salva la situazione: se il backend non risponde più, Nginx continua a servire l'ultima versione nota invece di un errore.

Su WordPress, PrestaShop o Laravel, un modulo di cache applicativa produce lo stesso effetto con meno rischi di effetti collaterali.

Come bloccare gli indirizzi recidivi con fail2ban?

Limitare rallenta; bloccare ferma. fail2ban legge i registri e aggiunge una regola di firewall contro gli indirizzi che attivano troppo spesso il limite.

apt install fail2ban

In /etc/fail2ban/jail.local:

[nginx-limit-req]
enabled  = true
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime  = 3600
systemctl restart fail2ban
fail2ban-client status nginx-limit-req

Letta ad alta voce, la regola dice: un indirizzo che attiva 10 volte la limitazione in 60 secondi viene bloccato per un'ora.

Quali impostazioni evitare di fronte a un attacco applicativo?

Queste impostazioni circolano molto e fanno più male che bene.

Da evitare Perché
Bloccare curl e wget in base allo user agent Un attaccante cambia agent con una riga. Lei invece rompe il Suo monitoraggio, i Suoi webhook di pagamento e i Suoi script di backup.
client_max_body_size 1k Ogni caricamento di immagine, ogni modulo un po' lungo, ogni aggiornamento del CMS fallisce.
allow su una sottorete e poi deny all Chiude il sito a tutta Internet, quindi ai Suoi visitatori. Riservi questo schema agli URL di amministrazione.
Bloccare interi paesi per riflesso Molti falsi positivi, e gli attaccanti noleggiano macchine ovunque.
Disattivare i registri «per prestazioni» Perde l'unico modo per capire che cosa Le sta succedendo.

Una regola semplice: ogni misura che blocca più largamente dello schema osservato si pagherà in clienti persi.

Quando conviene aprirci una richiesta di assistenza?

Quando il problema supera ciò che può risolvere sulla macchina: collegamento saturo, attacco prolungato o migliaia di indirizzi.

Apra una richiesta se:

  • la macchina resta inaccessibile nonostante queste impostazioni;
  • il traffico satura il collegamento di rete ancor prima di raggiungere Nginx;
  • l'attacco dura e proviene da migliaia di indirizzi diversi.

Alleghi alla richiesta gli estratti di log del punto 1 e la finestra temporale interessata. È ciò che ci permette di intervenire a monte, sulla rete, dove Lei non può agire.

Questo articolo ti è stato utile?