In questa sede ci limiteremo ad analizzare tutti gli aspetti che riguardano la configurazione di un buon firewall... In genere ogni distribuzione linux è fornita del suo firewall ed eventualmente di tools grafici di configurazione ma noi ci soffermeremo sulle opzioni e i parametri di iptables così da potere creare uno script di setup personalizzato per le nostre esigenze e soprattutto facile da modificare qualora fosse necessario.
Ovviamente c'è uno sproposito di documentazione a riguardo in rete... ci sono tutorial e guide molto approfondite e tradotte nelle più svariate lingue...
Tanto per cominciare elenchiamo qui qualche link utile:
Procediamo!
http://www.netfilter.org Il sito ufficiale del progetto netfilter/iptables. Quale posto migliore per trovare tutorial, esempi, ecc...
http://www.linuxguruz.com/iptables La sezione di linuxguruz dedicata ad iptables: ci sono decine di script da cui prendere spunto
Filtraggio
Il lavoro di un firewall consiste fondamentalmente nel "filtrare" i pacchetti I/O delle varie interfacce (lo, eth, ppp...) e bloccarli, respingerli, accettarli, inviarli e inoltrarli secondo una serie di regole definite dall'utente. Per filtrare i vari pacchetti, i kernel linux sono forniti della infrastruttura "netfiltrer", ovvero un framework generico in cui è possibile inserire moduli e lavorare al filtraggio. Tra i vari moduli c'è il tool di quarta generazione "iptables".
Iptables si occupa di dialogare con il kernel per inserire, rimuovere e modificare le regole nella tabella di filtraggio del kernel. Ciò significa che tutte le regole vanno perse allo spegnimento del sistema. E' facile immaginare come questo possa essere un problema nel momento in cui si raggiunge livelli di configurazione avanzata: è a questo punto che le tecniche di scripting ci vengono in auto permettendo di automatizzare la procedura di inizializzazione della tabella di filtraggio del kernel ad ogni avvio del sistema.
Il nostro programma si traduce quindi nel conoscere gli strumenti che iptables ci mette a disposizione per costruire poco alla volta il nostro script.
Il kernel ha tre liste di regole che vengono denominate CATENE. I loro nomi sono INPUT, OUTPUT e FORWARD e sono organizzate così:
Quando un pacchetto arriva ad una catena, può essere accettato (ACCEPT) o scartato (DROP). Le regole trattano l'intestazione del pacchetto: se il pacchetto non soddisfa una certa regola, si passa alla regola successiva e si prosegue ad oltranza. Nel momento in cui non ci sono più regole, viene attuata la tattica (policy) della catena che di solito è DROP._____
Ingresso / \ Uscita
-->[Decisioni]-->|FORWARD|------>
[di routing] \_____/ ^
| |
v ____
___ / \
/ \ |OUTPUT|
|INPUT| \____/
\___/ ^
| |
----> Processi locali --
Quando un pacchetto arriva, il kernel ne verifica la destinazione: se è destinato alla linux box corrente, il pacchetto viene inviato alla catena INPUT, altrimenti, a seconda che il forward sia attivato o no, inviato alla catena FORWARD o scartato (DROP).
Se invece un pacchetto viene inviato da un processo interno al sistema (deve uscire), il pacchetto viene inviato automaticamente alla catena OUTPUT e, se viene accettato, prosegue il suo cammino verso l'interfaccia cui è destinato.
Le operazioni
Le operazioni di cui disponiamo per mettere su il nostro firewall si possono dividere fondamentalmente in due categorie: le operazioni su intere catene e quelle sulle regole.
Premettendo che si parte con le tre catene di cui abbiamo già parlato e che queste non possono essere cancellate, le operazioni su intere catene sono:
Tali operazioni, indubbiamente comode per il loro ampio "raggio d'azione", ci serviranno in particolar modo nella prima parte del nostro script, dove provvederemo ad azzerare tutto per cominciare a costruire il nostro firewall da zero.Crea una nuova catena (-N). Cancella una catena vuota (-X). Cambia la politica di una delle catene preesistenti. (-P). Elenca le regole presenti in una catena (-L). Svuota una catena delle sue regole (-F). Azzera i contatori dei pacchetti e dei byte di tutte le regole di una catena (-Z).
Le operazioni per manipolare le regole di una catena sono:
Appendi una nuova regola alla catena (-A). Inserisci una nuova regola in una determinata posizione della catena (-I). Sostituisci una regola presente in una certa posizione della catena (-R). Cancella una regola presente in una certa posizione della catena (-D). Cancella la prima regola di una catena (-D).
L'utilizzo di queste operazione è naturalmente legato ad un buon
numero di flag e parametri che permettono di definire le regole con
precisione assoluta.
Vediamo più praticamente cosa significa operare sulla singola regola:
Lavoriamo in particore facendo uso dell'interfaccia di loopback così da poter operare tranquillamente restando sullo stesso sistema. Se usiamo il comando ping per generare pachetti ICMP verso l'indirizzo 127.0.0.1, otteremmo in risposta dei pacchetti ICMP tipo 0 (echo reply).
Proviamo allora a definire una regola di INPUT che scarti tutti i pacchetti ICMP provenienti dall'interfaccia di loopback:
La sintassi è chiara: "-A INPUT" appende una nuova regola alla catena INPUT; "-s 127.0.0.1" indica la sorgente (--source) che ci interessa; "-p icmp" specifica che ci limitiamo ad esaminare pacchetti dal protocollo icmp; "-j DROP" specifica cosa fare del pacchetto (--jump) (non specificare l'opzione -j si traduce nell'inserimento di una regola che non sortirà alcun effetto sui pacchetti che corrispondono a tutte le caratteristiche indicate).
Riprovando ora col comando ping, potemo verificare che non arrivino pacchetti in risposta: la regola funziona! In parole povere tutti i pacchetti di risposta vengono processati dal firewall e, rispondendo alle caratteristiche specificate nella nostra regola, verranno immediatamente scartati!
Per cancellare ora la regola appena inserita, possiamo usare due strade:
o
ATTENZIONE! E' possibile inserire inserire due o più regole perfettamente uguali nella stessa catena!
Arrivati a questo punto, le nostre conoscenze ci permettono, appoggiandoci opportunamente alla pagina man di iptables, di iniziare a costruire il nostro script personalizzato!
Lo script
Prima di costruire concretamente lo script è necessario fare una sorta di lavoro di preparazione: è necessario infatti avere ben chiara la posizione del firewall all'interno di un'eventuale rete e soprattutto quali sono i compiti che deve svolgere. In parole povere dobbiamo aver ben chiare le idee su quali politiche adottare per costruire un firewall che faccia esattamente ciò che ci si aspetta e che lo faccia nel modo possibile: una buona definizione delle politiche e delle regole può modificare sensibilmente la velocità della nostra rete!!!
Come primo esempio sceglieremo la situazione più classica: il computer in questione è collegato ad internet con una linea adsl e funziona da gateway per una piccola rete locale. Questo significa che lavoreremo principalmente sulle due interfacce ppp0 e eth0. In linea di massima accetteremo tutto il traffico proveniente dalla rete interna e bloccheremo tutto quanto proviene dall'interfaccia ppp0 se non espressamente richiesto o se indirizzato a porte che non ci interessano aperte per servizi come ssh ed ftp. Vediamo però passo passo come buttar giù un primo script.
Prima di tutto consideriamo l'idea di utilizzare qualche variabile in modo da poter adattare facilmente il nostro script se le impostazioni del nostro sistema dovessero cambiare:
Anche se il firewall perde tutte le impostazioni ad ogni avvio della macchina, è buona norma iniziare lo script con qualche riga che ripulisca tutte le catene e reinizializzi le policy:
Dedichiamoci quindi alla catena INPUT:
Il nostro obiettivo è quello di limitare l'input a due categorie di pacchetti: pacchetti relativi a connessioni già stabilite e pacchetti verso le porte dei servizi che noi vogliamo rendere pubblici.
Un errore che spesso si commette durante la configurazione di un firewall è quello di specificare esplicitamente su quali porte accettare input e quindi vietare tutto il resto: questa pratica è un buon punto di partenza, soprattutto se si vuole tenere il livello di protezione alto... ma in realtà va sviluppato poichè nasconde una piccola insidia: operando in questo modo, infatti, tutti pacchetti che arrivano su porte non esplicitamente lasciate aperte vengono scartati... e allora??? cos'è che non quadra??? provate ad aprire una pagine web e ve ne renderete conto... ^_^
In pratica dobbiamo aggiungere un altra regola che accetti tutte i pacchetti in input se appartengono a connessioni che abbiamo stabilito noi con l'esterno...
Vediamo più praticamente cosa significa operare sulla singola regola:
Lavoriamo in particore facendo uso dell'interfaccia di loopback così da poter operare tranquillamente restando sullo stesso sistema. Se usiamo il comando ping per generare pachetti ICMP verso l'indirizzo 127.0.0.1, otteremmo in risposta dei pacchetti ICMP tipo 0 (echo reply).
Proviamo allora a definire una regola di INPUT che scarti tutti i pacchetti ICMP provenienti dall'interfaccia di loopback:
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
La sintassi è chiara: "-A INPUT" appende una nuova regola alla catena INPUT; "-s 127.0.0.1" indica la sorgente (--source) che ci interessa; "-p icmp" specifica che ci limitiamo ad esaminare pacchetti dal protocollo icmp; "-j DROP" specifica cosa fare del pacchetto (--jump) (non specificare l'opzione -j si traduce nell'inserimento di una regola che non sortirà alcun effetto sui pacchetti che corrispondono a tutte le caratteristiche indicate).
Riprovando ora col comando ping, potemo verificare che non arrivino pacchetti in risposta: la regola funziona! In parole povere tutti i pacchetti di risposta vengono processati dal firewall e, rispondendo alle caratteristiche specificate nella nostra regola, verranno immediatamente scartati!
Per cancellare ora la regola appena inserita, possiamo usare due strade:
# iptables -D INPUT num
Dove num indica la posizione della regola nella catena
o
# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
Ovvero lo stesso identico comando usato per l'inserimento della catena, sostituendo "-A" con "-D".
ATTENZIONE! E' possibile inserire inserire due o più regole perfettamente uguali nella stessa catena!
Arrivati a questo punto, le nostre conoscenze ci permettono, appoggiandoci opportunamente alla pagina man di iptables, di iniziare a costruire il nostro script personalizzato!
Lo script
Prima di costruire concretamente lo script è necessario fare una sorta di lavoro di preparazione: è necessario infatti avere ben chiara la posizione del firewall all'interno di un'eventuale rete e soprattutto quali sono i compiti che deve svolgere. In parole povere dobbiamo aver ben chiare le idee su quali politiche adottare per costruire un firewall che faccia esattamente ciò che ci si aspetta e che lo faccia nel modo possibile: una buona definizione delle politiche e delle regole può modificare sensibilmente la velocità della nostra rete!!!
Come primo esempio sceglieremo la situazione più classica: il computer in questione è collegato ad internet con una linea adsl e funziona da gateway per una piccola rete locale. Questo significa che lavoreremo principalmente sulle due interfacce ppp0 e eth0. In linea di massima accetteremo tutto il traffico proveniente dalla rete interna e bloccheremo tutto quanto proviene dall'interfaccia ppp0 se non espressamente richiesto o se indirizzato a porte che non ci interessano aperte per servizi come ssh ed ftp. Vediamo però passo passo come buttar giù un primo script.
Prima di tutto consideriamo l'idea di utilizzare qualche variabile in modo da poter adattare facilmente il nostro script se le impostazioni del nostro sistema dovessero cambiare:
#!/bin/sh
# Variabili da impostare a seconda del proprio sistema
INTERNALIF="eth0"
INTERNALNET="192.168.1.0/24"
INTERNALBCAST="192.168.1.255"
EXTERNALIF="ppp0"
# Path di iptables
IPTABLES="`which iptables`"
Anche se il firewall perde tutte le impostazioni ad ogni avvio della macchina, è buona norma iniziare lo script con qualche riga che ripulisca tutte le catene e reinizializzi le policy:
####### INIZIALIZZAZIONE DEL FIREWALL #######
# Svuota la catena INPUT
$IPTABLES -F INPUT
# Svuota la catena OUTPUT
$IPTABLES -F OUTPUT
# Svuota la catena FORWARD
$IPTABLES -F FORWARD
# Ripulisci la Nat table
$IPTABLES -t nat -F
Dedichiamoci quindi alla catena INPUT:
Il nostro obiettivo è quello di limitare l'input a due categorie di pacchetti: pacchetti relativi a connessioni già stabilite e pacchetti verso le porte dei servizi che noi vogliamo rendere pubblici.
Un errore che spesso si commette durante la configurazione di un firewall è quello di specificare esplicitamente su quali porte accettare input e quindi vietare tutto il resto: questa pratica è un buon punto di partenza, soprattutto se si vuole tenere il livello di protezione alto... ma in realtà va sviluppato poichè nasconde una piccola insidia: operando in questo modo, infatti, tutti pacchetti che arrivano su porte non esplicitamente lasciate aperte vengono scartati... e allora??? cos'è che non quadra??? provate ad aprire una pagine web e ve ne renderete conto... ^_^
In pratica dobbiamo aggiungere un altra regola che accetti tutte i pacchetti in input se appartengono a connessioni che abbiamo stabilito noi con l'esterno...
####### COSTRUZIONE DELLA CATENA INPUT #######
# Accetta tutto il traffico che riguarda connessioni già stabilite
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Accetta tutto il traffico in input proveniente dall'interfaccia interna
$IPTABLES -A INPUT -i $INTERNALIF -s $INTERNALNET -j ACCEPT
# Accetta connessioni su queste porte
$IPTABLES -A INPUT -p tcp --dport 22 -j ACCEPT # SSH
$IPTABLES -A INPUT -p tcp --dport 80 -j ACCEPT # SERVER WEB
# Accetta tutto ciò che arriva dall'interfaccia locale
$IPTABLES -A INPUT -i lo -j ACCEPT
# Scarta tutto ciò che arriva alla catena INPUT e non rientra nelle regole precedenti
$IPTABLES -A INPUT -p all -j DROP
Passiamo ora alla catena FORWARD
####### COSTRUZIONE DELLA CATENA FORWARD #######
# Forwarda tutto il traffico che riguarda connessioni già stabilite
$IPTABLES -A FORWARD -i $EXTERNALIF -m state --state ESTABLISHED,RELATED -j ACCEPT
# Forwarda tutto il traffico proveniente dalla rete interna e diretto all'esterno
$IPTABLES -A FORWARD -o $EXTERNALIF -i $INTERNALIF -j ACCEPT
# Scarta tutto ciò che arriva alla catena FORWARD e non rientra nelle regole precedenti
$IPTABLES -A FORWARD -p all -j DROP
####### COSTRUZIONE DELLA CATENA OUTPUT #######
# Accetta tutto il traffico in uscita
$IPTABLES -A OUTPUT -j ACCEPT
####### VARIE #######
#Abilita il forwarding
echo 1 >/proc/sys/net/ipv4/ip_forward
# Maschera le connessioni interne verso l'esterno (attiva masqueradinig)
$IPTABLES -A POSTROUTING -t nat -o $EXTERNALIF -j MASQUERADE
Approfondimenti
Lo script appena costruito è
ovviamente solo una base da cui cominciare lo studio dei firewall:
molti degli how-to che si trovano in giro per la rete dicono
esplicitamente che è bene, per i newbie, cominciare con script
"minimalisti". Effettivamente il consiglio è validissimo: uno
script non troppo complesso, ma ben strutturato, assicura un discreto
livello di protezione senza imbarcarsi in opzioni varie che potrebbero
combinare più pasticci che altro. Tra esempi alla fine di questo
documento potrete trovare qualche altro script che coglie in pieno il
succo di questo pensiero ed è adattissimo per l'utilizzo su un
normale computer di casa.
Vedremo invece ora, come rinforzare il nostro script e come sfruttare le tecniche di logging per sapere sempre esattamente cosa succede sulla nostra rete ed eventualmente scoprire come e dove mettere qualche pezza.
Logging
Le tecniche di logging sono da sempre fondamentali per ogni buon amministratore di sistema: il logging ci permette di sapere di tutto e di più su quanto succede nel nostro sistema e noi lo utilizzeremo per monitorare il nostro traffico di rete. Un sistema di logging ben configurato ci permette di sapere se il nostro firewall funziona come previsto e se c'è bisogno di dare una regolata alle catene...
Una persona alle prime armi, di solito, è tentata da loggare direttamente qualsiasi cosa passi per il firewall, ma questo può essere un errore molto grave: loggare tutto, specialmente se si tiene aperti alcuni servizi, può produrre un eccesso di overhead. Anzi, tra le tecniche di attacco, c'è proprio questa.
E' bene allora pensare bene di cosa sia veramente necessario tenere traccia: torniamo quindi all'esempio di rete utilizzato per la creazione del nostro primo script.
A meno che non mi interessi per fare delle statistiche, non credo serva molto loggare i pacchetti che vengono dall'interfaccia interna, dal momento che lascio passare tutto. Ciò che invece è interessante monitorare, è il traffico in input proveniente dall'interfaccia esterna:
Monitorare quanto avviene sulla porta 80, soprattutto se pensiamo che i siti che ospitiamo sono rivolti al pubblico, non può interessarci più di tanto. Inoltre Apache ha già un suo sistema di log, e quindi lasciamo stare questa porta.
Abbiamo lasciata aperta la porta 22 per il server SSH. Il motivo per cui l'abbiamo fatto è quello di lasciarci una via di ingresso quando non siamo a casa e, di norma, vogliamo essere i soli ad usufruire di questo servizio: diventa a questo punto interessante monitorare questa porta per sapere se c'è qualcun'altro che prova a mettere le mani sul nostro sistema. Spesso capita che una persona che si ritrova per la prima volta a guardare un log del firewall, me compreso, si allarmi per il numero enorme di tentativi di connessione su molte delle porte del proprio sistema: in realtà ogni computer riceve ogni giorno segnali di questo tipo. I motivi sono tanti, basta pensare già solo al numero di portscanner attivi in giro per la rete... A questo punto allora ci si chiede quando e perchè è lecito allarmarsi. Beh, quando vedete che ci sono molti tentativi di connessione su una stessa porta da parte dello stesso ip... allora con molta probabilità qualcuno ce l'ha proprio con voi...
Il numero di porte del nostro sistema è sicuramente troppo grande per poter decidere singolarmente quali porte tenere d'occhio... e abbiamo già detto che monitorare tutto può essere deleterio... ecco allora che prenderemo la saggia decisione di controllarele porte corrispondenti ai servizi più comuni tipo ftp, telnet, ecc...
Questo ci permetterà di farci un'idea di chi tenta di connettersi al sistema e se si rende necessario pensare a modificare il nostro livello di sicurezza: ricordiamo che nel nostro esempio stiamo considerando una normale connessione casalinga e, in linea di massima, non abbiamo motivo di pensare che qualcuno in gireo per il mondo abbia uno smodato bisogno di sapere cosa c'è nel nostro pc...
Ma vediamo ora praticamente come modificare il nostro script per attivare il logging delle porte che ci interessa monitorare:
Altri esempiVedremo invece ora, come rinforzare il nostro script e come sfruttare le tecniche di logging per sapere sempre esattamente cosa succede sulla nostra rete ed eventualmente scoprire come e dove mettere qualche pezza.
Logging
Le tecniche di logging sono da sempre fondamentali per ogni buon amministratore di sistema: il logging ci permette di sapere di tutto e di più su quanto succede nel nostro sistema e noi lo utilizzeremo per monitorare il nostro traffico di rete. Un sistema di logging ben configurato ci permette di sapere se il nostro firewall funziona come previsto e se c'è bisogno di dare una regolata alle catene...
Una persona alle prime armi, di solito, è tentata da loggare direttamente qualsiasi cosa passi per il firewall, ma questo può essere un errore molto grave: loggare tutto, specialmente se si tiene aperti alcuni servizi, può produrre un eccesso di overhead. Anzi, tra le tecniche di attacco, c'è proprio questa.
E' bene allora pensare bene di cosa sia veramente necessario tenere traccia: torniamo quindi all'esempio di rete utilizzato per la creazione del nostro primo script.
A meno che non mi interessi per fare delle statistiche, non credo serva molto loggare i pacchetti che vengono dall'interfaccia interna, dal momento che lascio passare tutto. Ciò che invece è interessante monitorare, è il traffico in input proveniente dall'interfaccia esterna:
Monitorare quanto avviene sulla porta 80, soprattutto se pensiamo che i siti che ospitiamo sono rivolti al pubblico, non può interessarci più di tanto. Inoltre Apache ha già un suo sistema di log, e quindi lasciamo stare questa porta.
Abbiamo lasciata aperta la porta 22 per il server SSH. Il motivo per cui l'abbiamo fatto è quello di lasciarci una via di ingresso quando non siamo a casa e, di norma, vogliamo essere i soli ad usufruire di questo servizio: diventa a questo punto interessante monitorare questa porta per sapere se c'è qualcun'altro che prova a mettere le mani sul nostro sistema. Spesso capita che una persona che si ritrova per la prima volta a guardare un log del firewall, me compreso, si allarmi per il numero enorme di tentativi di connessione su molte delle porte del proprio sistema: in realtà ogni computer riceve ogni giorno segnali di questo tipo. I motivi sono tanti, basta pensare già solo al numero di portscanner attivi in giro per la rete... A questo punto allora ci si chiede quando e perchè è lecito allarmarsi. Beh, quando vedete che ci sono molti tentativi di connessione su una stessa porta da parte dello stesso ip... allora con molta probabilità qualcuno ce l'ha proprio con voi...
Il numero di porte del nostro sistema è sicuramente troppo grande per poter decidere singolarmente quali porte tenere d'occhio... e abbiamo già detto che monitorare tutto può essere deleterio... ecco allora che prenderemo la saggia decisione di controllarele porte corrispondenti ai servizi più comuni tipo ftp, telnet, ecc...
Questo ci permetterà di farci un'idea di chi tenta di connettersi al sistema e se si rende necessario pensare a modificare il nostro livello di sicurezza: ricordiamo che nel nostro esempio stiamo considerando una normale connessione casalinga e, in linea di massima, non abbiamo motivo di pensare che qualcuno in gireo per il mondo abbia uno smodato bisogno di sapere cosa c'è nel nostro pc...
Ma vediamo ora praticamente come modificare il nostro script per attivare il logging delle porte che ci interessa monitorare:
1.
# iptables -N no-conns-from-ppp0
# iptables -A no-conns-from-ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A no-conns-from-ppp0 -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A no-conns-from-ppp0 -i ppp0 -m limit -j LOG --log-prefix "Bad packet from ppp0:"
# iptables -A no-conns-from-ppp0 -i ! ppp0 -m limit -j LOG --log-prefix "Bad packet not from ppp0:"
# iptables -A no-conns-from-ppp0 -j DROP
# iptables -A INPUT -j no-conns-from-ppp0
# iptables -A FORWARD -j no-conns-from-ppp0
(Continua... Last Update 19/11/04 15:00)