Iptables for dummies: gestire il firewall su Linux

Mentre su Windows il firewall è un software aggiuntivo, su Linux il firewall è gestito da un modulo stesso del kernel: netfilter. Per configurare netfilter si utilizza l’utility da riga di comando chiamata iptables. Tutti i vari front-end grafici (FireStarter, UFW e altri) non fanno altro che impartire per voi i comandi su iptables, ma nessuno di questi vi consentirà mai lo stesso livello di personalizzazione del firewall che vi offre iptables stesso.

Innanzitutto cominciamo con un poco di teoria: a cosa serve il firewall?

Gli utenti Windows sono convinti che il firewall serva a controllare i programmi che dal proprio computer cercano di connettersi (il famoso pop-up che chiede il permesso per il programma specifico), ma noi siamo utenti Linux e non abbiamo il problema di fastidiosissimi programmi che si autoinstallano sul nostro computer e che poi fanno danno agendo come server (consentendo ad altri di connettersi in remoto alla nostra macchina) o come client (inviando informazioni riservate).

Un firewall in realtà è molto di più. Si tratta di un software in grado di controllare, filtrare e registrare tutte le connessioni che passano per il nostro computer. Un firewall ad esempio può essere impostato per impedire l’accesso a determinati siti internet, o può essere impostato per bloccare un indirizzo ip che ha fallito troppi tentativi di accesso al vostro computer.

Ce n’è davvero bisogno?

A questo punto è importante porsi una domanda: abbiamo veramente bisogno del firewall sul computer? Su Windows senza dubbio… ma su Linux? La risposta è che nel 99% dei casi, non abbiamo bisogno di un firewall. Il nostro computer, infatti, è impenetrabile dall’esterno. Sì, avete capito bene. Possiamo navigare su internet tranquillamente senza che nessuno possa accedere al nostro computer… a meno che non ci sia qualche programma in ascolto. Cosa significa che un programma è in ascolto? Prendiamo l’esempio di Apache, il più famoso e utilizzato server web. Di default, Apache si mette in ascolto sulla porta 80 del vostro computer (ce ne sono a disposizione 65536) e aspetta che un client gli chieda una risorsa (solitamente una pagina web). Quando questo avviene, la “serve” (server) al client che provvede a visualizzarla sul vostro computer.

In sostanza, un computer su cui gira Apache, è predisposto per accettare tutte le connessioni che arrivano sulla porta 80, ma se Apache fosse “spento” il computer rifiuterebbe tutte le connessioni su quella porta. È per questo che un computer che non “offre” niente, è invulnerabile dall’esterno. E questa è la situazione di default del classico computer per utilizzo desktop. Ubuntu, ad esempio, appena installato non ha neanche una porta aperta. Slackware ne ha qualcuna (ad esempio il server ssh), ma è pensato per utenti più esperti che quindi sanno quali servizi tenere aperti e quali no.

A questo punto, per scoprire se sul vostro computer ci sono servizi in ascolto, installate il software nmap e dal terminale date:

nmap localhost

Se scoprite che ci sono alcuni servizi in ascolto, la prima domanda che dovete porvi è: li uso? Mi servono? Se non li usate e non vi servono, è molto più sicuro disabilitarli rispetto al proteggerli con un firewall. Se vi servono, allora non potrete più usarli neanche voi una volta che avrete bloccato la porta col firewall. Magari vi servono solamente all’interno della vostra rete locale, ma se vi collegate ad internet tramite un router, anche queto non è un problema: il router infatti funziona come firewall fisico e se volete che una connessione dall’esterno raggiunga direttamente il vostro computer, dovrete allora impostare il router per redirezionare tutte i pacchetti che arrivano su una determinata porta direttamente all’indirizzo ip del vostro computer nella rete di casa (il famoso motivo per cui in molti non riescono ad ottenere id alti con e/amule). Senza contare che moltissimi software consentono di agire direttamente sui loro file di configurazione per esser messi in ascolto solamente sulla rete locale.

Allora, una volta per tutte: per l’utente desktop, il firewall su Linux è praticamente del tutto inutile.

Come funziona Iptables

Ok, evidentemente vi serve davvero configurare questo firewall (magari perchè gestite un server che è direttamente connesso ad internet). Vediamo allora come fare.

Iniziamo dicendo che iptables si compone di diverse “tabelle”: INPUT, OUTPUT e FORWARD. La prima tabella gestisce tutti i pacchetti in entrata, la seconda tabella gestisce tutti i pacchetti in uscita e la terza gestisce il redirezionamento dei pacchetti. Ogni tabella può essere riempita con alcune regole. Ogni pacchetto verrà esaminato sulla scorta delle regole inserite nella tabella apposita e non appena verrà trovata una regola applicabile al pacchetto, verrà immediatamente processato secondo quella regola; se nessuna regola è adatta al pacchetto in questione verrà applicata l’azione di default settata per quella tabella.

Facciamo un esempio banale:

TABELLA PER I PACCHETTI IN ARRIVO - DEFAULT RIFIUTA
1) Accetta tutte le connessioni sulla porta 22
2) Logga tutte le connessioni sulla porta 22
3) Accetta tutte le connessioni sulla porta 21
4) Accetta tutte le connessioni sulla porta 80

Un pacchetto che arriva ad un computer con questa tabella verrà verificato seguendo tutte le regole, in ordine, finchè non ne trova una che stabilisce se accettarlo o se respingerlo. È evidente allora che la tabella qui sopra contiene un errore: nessun pacchetto in arrivo sulla porta 22 verrà mai loggato, infatti l’esecuzione delle regole sui pacchetti in arrivo a quella porta si fermerà non appena viene verificata la prima regola. Se nessuna regola può essere applicata, allora verrà applicata la policy di default.

Possibili strategie

Si può decidere di procedere in due modi ben differenti, basati su una cosiddetta whitelist (ovvero tutti i pacchetti vengono rifiutati a parte quelli specificati) oppure su una blacklist (tutti i pacchetti vengono accettati tranne quelli specificati). L’approccio è molto differente, ma non esiste un metodo migliore.

Se avete seguito bene bene la guida, capirete che l’approccio basato su blacklist non è più rischioso di quello basato su whitelist. Infatti, se anche tutti i pacchetti venissero accettati, tuttavia in assenza di servizi in ascolto non ci sono rischi di alcun tipo. L’approccio su blacklist è comodo per quelle connessioni che avvengono su porte casuali (ad esempio ftp) per cui non è possibile prevedere in anticipo su quale porta accettare i pacchetti (sebbene i sistemi per permettere queste connessioni anche con whitelist non manchino).

Solitamente, si sceglie di utilizzare l’approccio basato su whitelist per i pacchetti in entrata e quello su blacklist per i pacchetti in uscita. Nulla vieta di fare diversamente, ma trovo che questa sia la soluzione che maggiormente si avvicina al nostro naturale modo di pensare.

Sporcarchiamoci le mani

È arrivato il momento di aprire il nostro terminale. Anzi no. Se vogliamo lavorare con calma, senza rischiare di “sbatterci fuori” dal nostro stesso sistema (rischio sempre in agguato se si configura un firewall in remoto), è meglio inserire tutti i comandi in uno script. Creiamo allora un file di testo e chiamiamolo come vogliamo, ad esempio firewall.sh. Scriviamoci dentro le seguenti righe:

# !/bin/bash
#
# Il mio script per iptables

A questo punto, se preferite, potrete incollare nel vostro script tutti i comandi che adesso vi mostrerò per poi eseguirli tutti insieme in un colpo solo. Io scriverò la guida come se voi stesse digitando i comandi direttamente sul vostro terminale.

Come già detto, se state lavorando in remoto tramite ssh, la prima cosa da fare è assicurarvi di non rendere impossibili a voi stessi il lavoro sul server. Cominciamo quindi dando i seguenti comandi:

iptables -P INPUT ACCEPT
iptables -F

Analizziamo subito questi due comandi.

L’opzione “-P” serve ad impostare la policy di default per un determinato canale. In questo caso noi stiamo dicendo alla macchina di accettare tutti i pacchetti che non corrispondono a nessuna delle regole inserite. La sintassi è molto semplice: iptables -P CANALE REGOLA.

L’opzione “-F“, invece, sta per “flush” e ha il compito di eliminare tutte le regole attualmente inserite. Dopo aver dato questo comando, la nostra macchina sarà predisposta per accettare tutte le connessioni in entrata, tutti i vostri servizi saranno raggiungibili dall’esterno (a patto che la vostra macchina sia connessa direttamente ad internet).

Adesso entriamo nel vivo della configurazione del firewall:

iptables -A INPUT -p tcp --dport ssh -j ACCEPT

Questo comando rispecchia la sintassi che, con buona probabilità, utilizzeremo più di frequente. La -A dice di “appendere” (ossia mettere alla fine) della tabella INPUT (ricordiamo che possiamo decidere di “appendere” regola anche ai canali di OUTPUT e FORWARD) una regola. La -p stabilisce il protocollo, nel nostro caso tcp perchè ssh utilizza questo protocollo (ma a seconda delle esigenze avremmo potuto scrivere anche udp o icmp). –dport stabilisce la destination port, ossia la porta a cui i pacchetti devono essere indirizzati: noi abbiamo scritto ssh, ma avremmo potuto scrivere anche direttamente il numero della porta (22). La -j invece stabilisce l’azione da intraprendere: noi ovviamente vogliamo che le connessioni su ssh vengano accettate (altrimenti non ci potremo più collegare al nostro server) e quindi abbiamo scritto ACCEPT. Qualora avessimo voluto rifiutare il pacchetto avremmo dovuto scrivere DROP, ma questo non avrebbe avuto molto senso poichè abbiamo deciso di utilizzare l’approccio su whitelist per la tabella di INPUT (quindi avremmo ottenuto lo stesso effetto non scrivendo alcuna regola). Avremmo anche potuto decidere di loggare il pacchetto. Questa è una possibilità molto utile quando si tratta di scoprire quali pacchetti vengono rifiutati per fare un debug delle eventuali applicazioni.

Adesso che siamo sicuri che la macchina accetti le nostre connessioni ssh, possiamo anche stabilire nuovamente DROP come policy di default della tabella INPUT. Non vi dico come fare, lo sapete già.

Bene. La sintassi per consentire l’accesso su tutte le altre porte è identica a quella utilizzata su ssh. Prima di proseguire, però, è importante aggiungere altre due regole importantissime, senza le quali è facile incappare in problemi di varia natura:

iptables -I INPUT -i lo -j ACCEPT
ipatbles -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Prima di spiegare cosa fanno queste due regole, facciamo attenzione ad un piccolo particolare: abbiamo usato -I e non -A. Con la seconda opzione queste due regole sarebbero state inserite alla fine della tabella, ma noi vogliamo che queste due vengano processate PRIMA di tutte le altre, poichè sono le due regole che compiono la stragrande maggioranza del lavoro. L’opzione -I fa esattamente questo: le inserisce all’inizio di tutte le altre. ATTENZIONE: quando usate -I la vostra regola diventerà automaticamente la prima dell’elenco, con -A invece essa sarà l’ultima.

Cosa fanno queste due regole? La prima è molto semplice: l’opzione -i ci consente di selezionare il traffico che passa per una specifica interfaccia di rete e noi abbiamo scelto l’interfaccia lo. Cos’è questa interfaccia? È l’interfaccia di loopback, ossia l’interfaccia su cui “viaggiano” i pacchetti che la macchina invia a se stessa. È grazie a questa interfaccia che potete aprire un terminale e pingare voi stessi. Questa regola quindi, dice al firewall di accettare tutti i pacchetti prodotti dalla stessa macchina su cui il firewall è attivo, sicuramente sono pacchetti innocui.

La seconda regola è un po’ più complicata e introduce uno dei pregi principali di iptables: i moduli. L’opzione -m dice ad iptables di utilizzare il modulo state, che consente di capire lo stato di un pacchetto, l’opzione –state (funzionante solo dopo aver caricato il modulo) consente di selezionare questi stati. Tre di questi stati sono particolarmente interessanti: NEW, ESTABLISHED e RELATED. NEW si riferisce a tutti i pacchetti che tentano di stabilire una nuova connessione, ESTABLISHED si riferisce alle connessioni già in corso, mentre RELATED si riferisce ad un pacchetto che tenta di stabilire una nuova connessione, ma questa richiesta è stata effettuata da una connessione già stabilita in precedenza. Cosa fa quindi questa regola? Dice al nostro firewall di accettare tutti i pacchetti relativi a connessioni già in atto o comunque a queste riconducibili.

Cosa sarebbe successo se fra gli stati della nostra regola avessimo aggiunto anche lo stato NEW? Semplicemente avremmo fatto in modo he il nostro firewall accettasse tutte le connessioni. Ricordiamo infatti che una volta che un pacchetto trova una regola buona per lui (e ogni pacchetto risulta positivo al test su NEW la prima volta e, successivamente, ai test su ESTABLISHED) il firewall smette immediatamente di processare il pacchetto e applica la regola.

Ecco. Il nostro firewall è pronto. Al momento consente solo le connessioni su ssh, ma utilizzando la stessa sintassi utilizzata per consentire queste connessioni, potrete aprire anche le porte del server web, del server smtp o ftp e così via.

Altri comandi d’esempio

Non è necessario aprire le porte una ad una. È possibile infatti utilizzare il modulo multiport per aprirne di più con un solo comando:

iptables -A INPUT -p tcp -m multiport --dport http,https -j ACCEPT

Le porte che vogliamo aprire vanno separate con una virgola.

Possiamo anche mettere al sicuro il nostro server ssh contro i tentativi di accesso tramite brute force:

iptables -A INPUT -p tcp --dport ssh -m recent --set --name ssh --rsource iptables -A INPUT -p tcp --dport ssh -m recent ! --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j ACCEPT

Sembra difficile, ma non lo è. Il primo comando utilizza il modulo recent per scrivere (–set) in una lista chiamata ssh (–name ssh) tutti gli indirizzi ip che tentano una nuova connessione (ricordiamo infatti che poichè il nostro firewall è settatato per accettare tutti i pacchetti con stato ESTABLISHED, una connessione ssh avvenuta con successo non verrà verificata più di una volta). Il secondo comando utilizza lo stesso modulo ma per verificare che lo stesso indirizzo ip non abbia fatto più di 4 tentativi negli ultimi 60 secondi. Se questa condizione non è verificata (a questo serve il punto escalamativo subito dopo il caricamente del modulo), la connession è accettata, altrimenti viene applicata la policy di default (che quindi dev’essere impostata su DROP per un corretto funzionamento di queste regole).

Conclusione

Io, qui, ho voluto darvi un assaggio di iptables. Spero di essere riuscito a trasmettervi almeno le competenze necessarie per capirne la complicata (ma in fondo non troppo) sintassi. Adesso non vi resta altro da fare che dare una lettura alla pagina di manuale che, sicuramente, la vostra distribuzione comprende: man iptables.

Bene, adesso ne sapete abbastanza su iptables per poter costruire il vostro firewall personale. Rircordatevi sempre di verificare che effettivamente ne abbiate bisogno.