Difendi il tuo server Web contro gli attacchi Distributed Denial of Services (DDos)

Nella sicurezza del computer, diventa subito evidente che prevenire gli attacchi informatici è molto più difficile che attaccare i computer. Un buon esempio di una tecnica semplice per impedire il corretto funzionamento di un sito Web è un attacco denial of service distribuito o DDoS, in cui un certo numero di computer compromessi su Internet fa richieste web (o di altro protocollo) su alcuni server poveri. Se la pagina Web richiesta è una che richiede molta elaborazione sul lato server, il carico risultante dalle richieste combinate impedisce al server Web di rispondere a richieste legittime, negando in tal modo il servizio. Poiché recentemente Tech-Recipes.com è stato sottoposto a un tale attacco, abbiamo ritenuto che avrebbe potuto essere di beneficio per gli altri se avessimo descritto i passaggi che abbiamo seguito nella nostra risposta.


Nota: le seguenti informazioni sono rilevanti per i server basati su UNIX che eseguono Apache (sebbene altre piattaforme e software potrebbero essere applicabili). Un prerequisito per questo approccio richiede l'uso di iptables che probabilmente significa che è necessario l'accesso di root al server, quindi questo probabilmente non ti aiuterà se stai usando l'hosting condiviso. Scusate! La cosa migliore da fare in questo caso è contattare l'ISP per il loro aiuto (buona fortuna) poiché è nel loro migliore interesse prevenire alti carichi sui loro server condivisi, anche se è probabile che disabilitino temporaneamente i servizi di dominio, che è sicuramente non la migliore soluzione dal tuo punto di vista.

Per ridurre al minimo l'impatto di un attacco denial of service, è necessario essere consapevoli dei problemi con il server Web quasi in tempo reale. Sono disponibili diversi servizi di monitoraggio server. Utilizziamo sia Pingdom che SiteUptime. Utilizzando questi servizi, abbiamo notifiche ridondanti di qualsiasi interruzione del servizio inviata ai nostri telefoni cellulari tramite SMS e a diversi indirizzi e-mail (nessuno dei quali è gestito dai nostri server monitorati, ovviamente). Utilizzando questi servizi, riceviamo una notifica entro un minuto dalla mancata richiesta ai nostri server di produzione.

Prima di implementare specifiche tecniche anti-DDoS o cercare aiuto da un servizio di protezione DDos, è opportuno assicurarsi che il problema sia in realtà un attacco DDoS. I servizi potrebbero non riuscire a rispondere a una richiesta per una serie di motivi tra cui l'eseguibile che esegue il servizio in modo imprevedibile, l'ISP che ospita il server che sta subendo un'interruzione della rete o del server, o qualche altra anomalia autocorrettiva nella matrice. Per determinare se l'errore di servizio è dovuto a un DDoS e per raccogliere le informazioni necessarie per intraprendere azioni contro l'attacco, è necessario scavare prima.

Devi accedere al tuo access_log, il file di log che contiene una voce di testo per ogni richiesta fatta al tuo web server. Ci sono molti posti che questo file può nascondere e dipende dalla configurazione del tuo server. In caso di dubbio, è possibile controllare la documentazione dell'ISP (cercare il log di accesso) - i dati del registro potrebbero essere accessibili tramite una console Web, ma è ottimale se si ha accesso alla shell al proprio server. Se la guida in linea dell'ISP non è così utile per trovare il registro di accesso, è possibile utilizzare il comando di ricerca di UNIX.

Una volta trovato il tuo log di accesso, cd nella directory contenente il log ed esegui il comando tail su di esso con l'opzione -f:

tail -f access_log

Il comando tail da solo visualizzerà le ultime 10 righe del file specificato e quindi uscirà. L'opzione -f indicherà tail per continuare a funzionare dopo che sono state visualizzate le ultime 10 righe e continuano a visualizzare le righe successive che vengono aggiunte al file. Probabilmente vedrai una moltitudine di voci. Se non vedi alcun messaggio di registro dopo il valore predefinito 10, stai guardando il file sbagliato o il server web è morto o non vede alcun traffico. È possibile che un server possa ospitare molti siti Web e ognuno di essi possa avere un file access_log separato, quindi assicurati di stare dietro a quello giusto. Se il servizio è morto, rianimalo attraverso qualsiasi meccanismo appropriato. Assumeremo da qui in avanti che stai vedendo un sacco di messaggi di log di accesso che sembrano molto simili (probabilmente colpiscono lo stesso URL) che non hanno un referrer valido o qualsiasi (se il referrer è slashdot.org o digg.com, beh, allora puoi essere felice e triste che il traffico, anche se server paralizzante, è legittimo) e avere un sacco di indirizzi IP diversi. Durante il nostro recente assedio, ci sono state così tante richieste fasulle che pochissime richieste legittime sono arrivate al file access_log. Ecco alcune righe del nostro access_log durante l'attacco:

220.255.7.204 - - [07 / Jul / 2008: 19: 28: 18 -0700] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 0 "-" "Mozilla / 4.0 (compatibile; MSIE 6.0 ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) "

220.255.7.209 - - [07 / Jul / 2008: 19: 28: 18 -0700] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 0 "-" "Mozilla / 4.0 (compatibile; MSIE 6.0 ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) "

220.255.7.208 - - [07 / Jul / 2008: 19: 28: 18 -0700] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 0 "-" "Mozilla / 4.0 (compatibile; MSIE 6.0 ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) "

71.232.78.53 - - [07 / Jul / 2008: 19: 28: 19 -0700] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 14313 "-" "Mozilla / 4.0 (compatibile; MSIE 7.0 ; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) "

Se non si ha familiarità con la struttura predefinita di access_log di Apache, il primo valore è l'indirizzo IP di origine della richiesta, quindi la data e l'ora della richiesta sono tra parentesi quadre e la prima stringa tra virgolette è la richiesta HTTP fatto. Nel nostro esempio, la richiesta era sempre la stessa: "GET /modules.php?name=Forums&file=index HTTP / 1.1" - una richiesta GET dell'URL (/modules.php?....) E il protocollo HTTP utilizzato (1.1 ).La porzione dell'URL utilizzata è importante poiché è l'unica cosa che possiamo usare per identificare gli indirizzi IP offensivi. La seconda stringa tra virgolette è l'URL di riferimento, nel nostro caso non ce n'è una, quindi si presenta come "-" che dà credito al sospetto che si tratti di un attacco DDoS. La stringa rimanente descrive la piattaforma e il software che ha effettuato la richiesta e non è molto significativa o utile per noi in quanto può essere facilmente falsificata.

Ora che sappiamo che è in corso un attacco DDoS, abbiamo bisogno di un elenco degli indirizzi IP coinvolti nell'attacco per bloccare le loro successive richieste con iptables. Nell'esempio access_log sopra, so che il componente URL richiesto "/modules.php?name=Forums&file=index" può essere usato per cercare attraverso access_log. Perché contiene caratteri speciali come & e? che la maggior parte delle shell UNIX interpretano come qualcosa di molto diverso, è una buona idea mettere la stringa di ricerca tra virgolette doppie in tutti i comandi che la usano. Il seguente comando catturerà solo quelle righe in access_log che corrispondono al componente URL sopra riportato e restituirà un elenco di indirizzi IP che lo richiedevano e un conteggio di quante volte ogni indirizzo IP ha fatto la richiesta, ordinata in base al conteggio.

fgrep "/modules.php?name=Forums&file=index" access_log | taglia -d \ -f1 | ordina -n | uniq -c | ordina -rn

Il comando fgrep è un grep veloce che non cerca espressioni regolari e può strappare enormi file di log in modo molto più efficiente. Se il tuo sistema non lo ha per qualche motivo insondabile, sostituisci il vecchio programma grep per fgrep. Sostituire il nome del registro di accesso se è diverso da access_log. Notare che ci sono due spazi dopo il backslash nell'opzione cut -d \. Questa stringa di comandi estrae le linee corrispondenti in access_log (fgrep), estrae il primo campo separato da spazi (taglia), li ordina numericamente (sort -n), li raggruppa per creare un elenco di indirizzi IP univoci e conta le occorrenze (uniq) e ordinarli numericamente in ordine inverso in modo che gli indirizzi IP con i conteggi più alti vengano prima. Ecco un esempio dell'output:

21889 71.232.78.53
17181 220.255.7.208
16162 220.255.7.209
16142 220.255.7.204

È probabile che vedrete due gruppi, alcuni indirizzi IP con un numero elevato (centinaia, migliaia) di richieste e alcuni con poche, forse decine di richieste. Quando si seleziona il numero di richieste che separa i due gruppi, fare attenzione poiché non si desidera bloccare richieste legittime. È probabile che quando inizi a bloccare gli indirizzi IP dalla cima dell'elenco, saprai quando i numeri cambieranno e diventeranno valori apparenti legittimi, come un salto da molte centinaia di colpi a poche decine di colpi. Se puoi, copia l'output del comando sopra in una qualche forma di editor di testo per tenerti a portata di mano. Una nota, se il tuo access_log non viene ruotato frequentemente (il suo contenuto viene copiato in un'altra posizione e probabilmente compresso), può diventare enorme. Puoi usare il comando tail in un modo diverso per rendere questo comando più veloce, che probabilmente il tuo server assillato apprezzerà: il comando "tail-10000 access_log" prenderà le ultime 10.000 righe da access_log e continuerà ad elaborarle (puoi cambiare 10000 a un numero di tuo gradimento):

tail -10000 access_log | fgrep "/modules.php?name=Forums&file=index" | taglia -d \ -f1 | ordina -n | uniq -c | ordina -rn

Ora che sei armato della conoscenza di quali indirizzi IP devi bloccare, è giunto il momento di stabilire la legge iptable. Il sistema iptables è in grado di eseguire diverse operazioni e, fortunatamente per noi, bloccare un singolo indirizzo IP è una delle configurazioni più semplici. Per bloccare tutte le richieste da un indirizzo IP come 71.232.78.53, utilizzare il comando:

iptables -A INPUT -s 71.232.78.53 -j DROP

Se non hai effettuato l'accesso al server come root, aggiungi un 'sudo' davanti a questo comando e fornisci la tua password quando richiesto. Questo comando aggiunge una regola temporanea al sistema iptables per eliminare tutti i pacchetti provenienti dall'indirizzo IP specificato. Questo effetto è temporaneo in quanto non persisterà dopo un riavvio. Se vuoi rendere permanenti questi cambiamenti (probabilmente non è una buona idea, ma non è poi così male, se hai intenzione di riavviare presto per liberare la memoria trapelata), puoi provare a correre

/etc/init.d/iptables save

Questo comando funzionerà e ti informerà che ha funzionato o che genererà un errore. In quest'ultimo caso, è possibile ripetere i comandi iptables, uno per indirizzo IP, per rebloccarli.

Se si hanno richieste provenienti da un numero di indirizzi IP all'interno della stessa sottorete, è possibile bloccare la sottorete in un comando iptables. Nel nostro caso, abbiamo avuto un sacco di indirizzi IP dalle richieste di invio di subnet 220.255.7.0. Piuttosto che ripetere il comando iptables un paio di centinaia di volte, la scorciatoia subnet per il comando iptables rende questa operazione molto più semplice:

iptables -A INPUT -s 220.255.7.0/24 -j DROP

Non vorrei bloccare più di una sottorete di classe C alla volta, come mostrato sopra. In sostanza, se vedi un gruppo di richieste da indirizzi IP in cui i primi tre numeri dell'indirizzo IP sono gli stessi, allora sono tutti nella stessa sottorete di classe C e puoi bloccarli tutti usando i primi tre numeri separati da un punto seguito da un .0 / 24 come sopra.

Poiché un attacco DDoS potrebbe essere in corso e più macchine potrebbero prendere parte all'attacco nel tempo, potrebbe valere la pena di fare uno script veloce per bloccare semplicemente un indirizzo IP. Ho scritto il seguente script e l'ho inserito in / usr / sbin / block

#! / Bin / bash

iptables -A INPUT -s $ 1 -j DROP

Una volta che il file è a posto, renderlo eseguibile con chmod + x / usr / sbin / block e quindi usarlo come:

blocco 71.232.78.53

Ogni sistema è unico, ha diverse applicazioni e versioni di applicazioni installate in luoghi diversi, quindi il tuo chilometraggio può variare a seconda delle istruzioni sopra riportate.