0x0001
Come...
Il presente ha l'intenzione di fornire una panoramica semplice sulla
macchina degli stati, con le stesse motivazioni dell'
altro scritto qui disponibile.
Tengo comunque a precisare che questa non è una spiegazione
ufficiale nè implementativamente corretta, ma solo
semplice.
Pertanto i particolari vengono citati in maniera vaga, e solo a esclusivo
scopo della migliore comprensione possibile.
Tuttavia, la comprensibilità di una astrazione può essere
decisamente soggettiva.
Quella che riporto è l'esemplificazione che ho utilizzato nei corsi
da me tenuti in passato, e che mi è sembrata essere la più
efficace. Se volete proporre spiegazioni alternative che a vostro giudizio
sono più comprensibili, lo farete a vantaggio della chiarezza del
presente nonchè dei miei corsi...
;-)
Se avete consigli, quindi,
contattatemi.
0x0002
...cosa...
Innanzitutto, cosa è la macchina di state?
La macchina di state è semplicemente un algoritmo, implementato
all'interno di netfilter, che provvede a correlare tra loro pacchetti che
altrimenti, dovrebbero essere gestiti "uno a uno". In tal modo possiamo
avere maggiori informazioni di quelle semplicemente portate con sè
dal pacchetto stesso, derivandole dal "dove si inserisce il pacchetto
nello stato attuale delle comunicazioni in essere".
Il concetto di macchina di state esiste su tutti i firewall che siano
dichiarati come "stateful", anche se prestazioni, comportamento e grado
di ispezione possono variare abbondantemente. Qui verrà data una
panoramica molto generica di come si comporta netfilter, ma se vi interessa
l'argomento, vi invito vivamente a vedere come funziona
PF su
OpenBSD,
oltre ovviamente a approfondire netfilter sulla
apposita documentazione.
0x0003
...perchè...
I protocolli di rete, come sapete, sono stratificati uno sull'altro.
Http funziona sopra TCP, il quale funziona sopra IP. Se lo strato IP
va in errore durante la comunicazione (ad esempio perchè la
macchina che si sta tentando di raggiungere non è in rete) le
notifiche verranno inviate facendo uso del protocollo ICMP.
Per gestire un banale web-browsing, vengono già tirati in ballo
ben 4 protocolli. E HTTP è un protocollo decisamente semplice,
da questo punto di vista...
Ora, prendiamo un client HTTP (una macchina con un browser, insomma...)
e mettiamola dietro un firewall.
Questo firewall deve permettere al client di navigare, e a tal scopo
deve lasciar passare le richieste provenienti dal client e dirette
alla porta 80 dei server fuori.
Altrettanto ovviamente, deve permettere ai server contattati di rispondere.
Perciò, consente le comunicazioni provenienti dalle porte 80 dei
server fuori e diretti al client interno.
Un primo problema che dovrebbe saltare all'occhio è che, in una
tale situazione, chiunque usi come sorgente per una comunicazione la
porta 80 e cerchi di connettersi ad una delle nostre macchine protette
viene immediatamente fatto passare.
Nel caso del protocollo HTTP è possibile comunque "metterci una pezza",
facendo in modo di lasciar passare i pacchetti che presentano il flag SYN
(quello di inizio connessione) attivo solo in una delle due direzioni.
Questo ha l'effetto di consentire comunque a chi sta all'esterno di
comunicare con l'interno, ma non di instaurare una nuova connessione,
proprio perchè il primo pacchetto viene droppato. Se il protocollo
utilizzato fosse stato UDP (come ad esempio nel caso di un server DNS),
ciò non sarebbe stato possibile, poichè non esiste in UDP
il concetto di sessione.
Altra annotazione riguarda invece un eventuale pacchetto ICMP che venga
rimandato indietro perchè la macchina di destinazione risulta
irraggiungibile.
Tali notifiche dovranno ovviamente essere lasciate passare, al fine di non
inficiare le funzionalità legate agli stessi. Dato poi che non esiste
modo per identificarle di per sè come "di risposta", vale per essi la
stessa cosa detta per UDP: tocca lasciarli passare tutti.
Da tutto ciò possiamo trarre alcune conclusioni:
- Un firewall che non possa correlare il traffico ( ovvero
stateless ) risulta, a parità di realizzazione, meno
sicuro, poichè non consente di capire quali pacchetti
bisogna far passare e quali invece si possono scartare,
costringendo, di fatto, a far passare anche traffico non
necessario.
- Un firewall stateless, a parità di funzionalità,
risulterà probabilmente più complesso da realizzare.
0x0003
...e dunque...
La macchina di state permette di identificare i pacchetti riferendosi
ad essi in funzione delle caratteristiche di stato, ignorando (volendo)
le altre caratteristiche. Gli stati usati per "catalogare" i pacchetti
sono:
- INVALID: Sono pacchetti che non hanno alcuno stato valido.
Hanno caratteristiche per le quali, fondamentalmente, non dovrebbero
esistere in alcuna comunicazione "normale".
- NEW: Rappresentano il primo pacchetto di una comunicazione.
Qualsiasi comunicazione inizia con un NEW, e pertanto sarà
su questo stato che andremo a decidere quali "servizi" lasciar
passare. Una volta che l'unico NEW di una comunicazione sarà
stato abilitato, tutti gli altri pacchetti di tale comunicazione
risulteranno appartenere ad altri stati.
- ESTABLISHED: Sono la continuazione di una comunicazione in cui
si sia già lasciato passare il NEW. Ovviamente, se l'inizio
della comunicazione non viene accettato, questa non può
proseguire, pertanto non si arriverà mai alla ESTABLISHED.
Altrettando ovviamente, se si accetta una NEW senza poi accettarne
i relativi ESTABLISHED, la comunicazione non può proseguire,
rendendo l'accettazione della NEW inutile salvo casi molto
particolari.
- RELATED: Rappresentano i pacchetti che non fanno strettamente
parte di una comunicazione in essere, ma in qualche modo "c'entrano".
In tale categoria rientrano ad esempio gli ICMP relativi una
comunicazione la cui NEW sia stata accettata. Sono compresi anche i
casi di comunicazioni parallele ad una connessione in essere e da
questa "originati"; esempio classico è rappresentato dalla
sessione dati di una connessione ftp. In quest'ultimo caso è
necessaria la presenza di un apposito modulo, specifico per
l'applicazione che usa la sessione, al fine di poter "tracciare" a
livello di applicazione le caratteristiche delle nuove connessioni
richieste (nel caso di ftp, il modulo ip_conntrack_ftp) prima che
queste vengano effettivamente aperte.
Vediamo come utilizzare tutto ciò, creando ad esempio, un piccolo firewall che
abbia lo scopo di chiudere completamente una macchina, concedendo l'ingresso
solo alle risposte di comunicazioni iniziate dalla macchina stessa.
# Setto tutte le policies a DROP. La FORWARD non la bado tanto non c'è.
iptables -P INPUT DROP
iptables -P OUTPUT DROP
# Per prima cosa abilito tutto quanto transita sulla loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Accetto tutte le nuove connessioni in uscita, ovviamente nella chain di OUTPUT
# insieme con i pacchetti successivi appartenenti alla stessa comunicazione
iptables -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Infine accetto in input solo quanto arrivi in risposta a quanto già accettato.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
...continua