Inhalt
Das Internet ist vom Forschungsplatz von Militär und Universitäten und Platz der Hacker und Nerds zum Massenmedium geworden. Die ganze Welt stellt den Begriff "Hacken" in zwiespältiges Licht und verbindet ihn direkt mit Einbruchsversuchen in Computer. Inzwischen fühlt sich nichteinmal mehr der Standardinternetuser (Email, Bild.de, Pornoseiten) sicher vor Angriffen aus dem Internet. Geschützt wird sich mit proprietärer Software von verschiedenen, spezialisierten Firmen oder gleich direkt mit Produkten aus dem Hause des Evil Empire.
1. Niemand ist sicher
2. Die Angst vor einem "Einbruch" basiert dennoch meist nur auf Unwissen
3. Es gibt freie Firewallsysteme - eines direkt im Linuxkernel. Warum also auf seine Freiheit verzichten?
In diesem Howto - inzwischen die 3. ([wie immer] verbesserte) Auflage, beschreibe ich den Aufbau der Linux-Firewall Netfilter und die richtige Konfiguration mit Hilfe von IPTables. Diese mächtige Kombination braucht den Vergleich mit kommerziellen Lösungen keineswegs zu scheuen und kann durchaus auch in Sicherheitskritischen Bereichen Einsatz finden. Wichtig sind Verständnis für Funktionsweise und Konfiguration und solltest du das Howto gelesen und verstanden haben, bist du selbigen ein Stück näher. Sollte etwas unklar oder Wünsche offen bleiben: Email an Tam (at) TeamUnix.de oder einen Kommentar zum Howto schreiben mit deiner Bitte drin. Und jetzt viel Spaß beim lernen. :-)
Netfilter ist ein von Paul Russel gestartetes Projekt, dessen Sinn es war die Firewall "IPChains", die in Linux 2.2 implementiert ist, durch etwas besseres zu ersetzen.
NAT steht für "Network Address Translation" und bietet die Möglichkeit Pakete zu verändern, bevor sie durch andere Firewallregeln laufen oder den Rechner verlassen.
IPTables nennt man schlussendlich das Frontend, das benutzt wird um Zugriff auf die Netfilter Kernelfunktionen zu erhalten.
Richtig konfiguriert findet sich in Netfilter eine mächtige Firewall. Im nächsten Kapitel gehen wir ein wenig ins Detail, bevor wir zur Praxis kommen.
IPTables arbeitet, wie der Name bereits vermuten lässt mit Tabellen (Tables) Diese sind per default "filter", "nat" und "mangle" - wobei die letztere für Sonderzwecke verwendet werden kann, die uns hier nicht interessieren brauchen.
Diese Tables besitzen verschiedene Chains (Ketten), die Regellisten bezeichnen.
Konzentrieren wir uns auf die filter und die nat Tabellen:
nat besitzt als Chains: PREROUTING, POSTROUTING und OUTPUT, filter dagegen INPUT, FORWARD und OUTPUT
Diese Chains spiegeln Netfilter "Hooks" im Kernel wieder und man kann für sie Regeln erstellen, wie sie sich verhalten sollen, wenn ein Paket einen solchen Hook passiert auf dem Weg zum, von oder durch den Computer ist.
Schauen wir uns dazu ein kleines ascii-art Kunstwerk an:
oO(Netz)Oo -> PREROUTING -> [ ROUTING ] -> FORWARD -> POSTROUTING -> oO(Netz)Oo
| ^
V |
INPUT [ ROUTING ]
^
|
OUTPUT
Links und rechts liegt irgendein Netzwerk, unten liegt der Computer. Ein Paket huscht also rein, mögliche Adressen werden für neue Verbindungen per NAT abgeändert, ein Routingmechanismus entscheidet ob das Paket weitergegeben werden soll oder für den lokalen Rechner bestimmt ist und so weiter.
Den Netfilterhooks sollen nun Regeln auferlegt werden, wie sie ein Paket behandeln sollen, das sie zu Gesicht bekommen - wenn also das Routing ein Paket durch diesen Hook schickt.
Das realisiert IPTables durch Targets (Ziele), ein Schicksal für das Paket, wenn eine Regel auf dieses zutrifft.
Targets für die Filter-Table sind: ACCEPT (annehmen), DROP (wegwerfen - die Gegenseite bekommt hierbei keine Antwort)und REJECT (zurückweisen - die Gegenseite bekommt hier eine RFC-konforme Fehlermeldung zugeschickt, die obendrein noch frei gewählt werden kann *g*) und auch LOG und ULOG, aber diese wirken nicht aktiv auf die Pakete ein und werden deshalb hier vernachlässigt).
Der Nat-Table dagegen stehen SNAT (Source NAT) und DNAT (Destination NAT) zur Verfügung. Wie die Namen vermuten lassen, kann man mit SNAT die Quelladresse eines Paketes ändern und bei DNAT die Zieladresse - sowie auch die verwendeten Ports.
Eine weit verbreitete Anwendung von SNAT und auch als eigenes Target realisiert, ist das sogenannte Maskieren. Mit dem Target MASQUERADE kann man ein ganzes Netzwerk hinter eine andere IP als Maske stecken. Verwendung findet dies bei DialUp Verbindungen mit dynamischen IPs. MASQUERADE ist in der Lage die IP eines Netzwerkinterfaces automatisch zu finden, also hat man im einfachsten Fall einen Linuxrouter in der Ecke stehen, der mit einer Netzwerkkarte an ein DSL Modem angeschlossen ist und mit der anderen am internen Netzwerk hängt. Alles was nun aus dem internen Netz kommt muss mit der öffentlichen IP (des Interfaces am Modem) maskiert werden, damit ein Webserver im Internet auch an diese zurückschicken kann. Der Router hingegen muss wissen, an welche IP im internen Netz er die Antwort vom Webserver nun schicken soll, aber darum muss man sich nicht explizit kümmmern, da Netfilter sogenanntes Connection Tracking (Conntrack) beherrscht.
Das bedeutet Netfilter ist in der Lage Pakete, die Antworten auf bereits aufgebaute Verbindungen sind zu erkennen und an den richtigen Rechner weiterzuleiten.
Hierraus geht ein weiteres Feature von Netfitler/IPTables hervor: Mithilfe von IPTables kann man den Status einer Verbindung abfragen. Dieser kann NEW (neu), ESTABLISHED (aufgebaut) oder RELATED (hängt mit bereits aufgebauter Verbindung zusammen) sein, so wie andere hier nicht relevante Stati. Dieses Feature macht Netfilter zu einer "Stateful Firewall".
Alles gar nicht so schwer!
Betrachten wir das ganze vereinfacht, nur mit Hilfe der Filter-Table.
Die Chains der Filter-Table sind wie bereits genannt INPUT, OUTPUT und FORWARD, wobei letzteres für Router besonders wichtig ist. Eigentlich selbsterklärend gehen eingehende Pakte an Input (vergleich mit Grafik), ausgehende an Output und alles was weitergeleitet wird an Forward.
Ein ankommendes Paket wird nun von oben nach unten durch die INPUT-Chain wandern. Trifft eine Regel auf das Paket zu (Es wird die allererste genommen, also vorsicht mit der Reihenfolge) so wird sie angewand. Trifft keine Regel zu wird die "Policy" verwendet.
Das ist also die Regel für alles das keine hat. Die sollte sinnvollerweise DROP lauten (wegwerfen).
Der Aufbau ist einfach:
Was nicht durch eine Regel erlaubt wird, kommt in den Müll, denn wenn man was vergisst zu erlauben, merkt man das recht schnell... aber umgekehrt bringt die Firewall gar nix mehr, denn alles was man vergisst zu sperren wird ja durchgelassen ;)
Machen wir also eine kleine Exkursion:
Paket Roland saust auf deine Firewall zu! Von der Ip 144.254.3.4 will es einen Webserver auf deinem PC erreichen (Port 80). Zuerst knallt Roland mit dem Kopf vor die Tür :D Danach macht er sich auf die Suche nach Klingel 80, *klingeling*... Herr INPUT öffnet die Türe und schaut Roland abschätzend an. Sein Meister hat ihm folgendes aufgeschrieben:
Chain Haustür (policy DROP)
DROP all -- 192.168.0.0/24 anywhere
ACCEPT tcp -- anywhere anywhere tcp dpt:auth
ACCEPT tcp -- anywhere anywhere tcp dpt:www
(nur ein kleiner Ausschnitt aus "
iptables -L" aber er reicht - es handelt sich um das Interface mit der öffentlichen IP!)
Also fängt er mal oben an....
Input:
"Kommen sie von irgendeiner 192.168.0.*** Firma ?" (also jemand der sich für einen Hausangestellten ausgibt, aber in Wahrheit von außen kommt)
Roland:
"Nein"
Input:
"Gut.. weiter... *grübel* hatten sie bei 113 (auth)
geklingelt ?"
Roland:
"Nein"
Input:
"Klingel 80 ? (http)
"
Roland:
"Ja"
Input:
"Dann rein mit dir! - Du hast Glück... hättest du auch dieses mal nein gesagt hätte ich dich in den Abfalleimer dort drüben geworfen" :D
Der Vergleich hinkt etwas, da Roland eigendlich seine IP und Port etc auf der Stirn geschrieben steht. Aber wir nehmen an er lügt nicht... Vielleicht ist dir aufgefallen das Roland nur im Stande ist Ja oder Nein zu sagen... demensprechend muss der Meister von Herrn Input die Fragen sehr treffend formulieren.
Wichtig ist auch, dass Herr Input den Zettel quasi jeden Tag verliert... nach jedem Reboot ist die Konfiguration weg und du musst alles neu machen (was nicht tragisch ist als Shellscript)
Soviel zum allgemeinen. Gehen wir näher auf die Handhabung ein.
Vorab: ich erwähne hier nur die Funktionen die benötigt werden um eine gut funktionierende Firewall und Router zu erstellen.
Wichtig: Wenn nicht explizit mit "-t" eine Table angegeben wird, nimmt IPTables die Fitler-Table als default an!
Eine neue Regel erstellt man mit:
"
iptables"
Gefolgt von verschiedenen Parametern, die wenn sie nicht angegeben werden einfach für alles gelten. Also je mehr Parameter, desto genauer werden Pakete eingegrenzt. Ein "!" nach der option (zB. -s ! 127.0.0.1 oder -p ! tcp) bedeutet: 'außer'.
"
-A INPUT"
APPEND - hängt einen Eintrag hinten an die INPUT-Chain an (das war alles, was für den lokalen Rechner bestimmt ist)
"
-N sperre"
NEW - erstellt eine neue Kette namens sperre
"
-F INPUT"
FLUSH - löscht den Inhalt einer Kette (wenn man ein Shellscript macht sollte man das unbedingt verwenden, wenn man die vorhandene Konfiguration ohne Neustart übernehmen will, denn sonst werden ja nur Befehle angehangen und die Kette einfach länger und länger)
"
-t nat"
TABLE -wählt eine spezielle table aus zB nat (zum routen)
"
-i interface"
IN INTERFACE - interface ist ippp0 oder eth0 öder ähnliches, es Bezeichnet die Hardwareschnittstelle, auf der Das Paket ankommt. (nur möglich in der INPUT- und FORWARD-Kette)
"
-o interface"
OUT INTERFACE - das gleiche, gilt aber nur für OUTPUT und FORWARD
"
-s 127.0.0.1"
SOURCE - gibt die Quell-IP an von der das Paket kommt, auf das die Regel zutreffen soll. (man kann Hostnamen wie www.fuckmicrosoft.com (Was aber unbedingt vermieden werden sollte, da sonst DNS redirecting attacken zum durchlöchern der Firewall eingesetzt werden könnten!) oder IP-Addressen ebenso verwenden wie Adressbereiche ala 192.168.0.0/24 (das bedeutet alle Addressen, die mit 192.168.0. beginnen matchen; Als letztes Byte der IP wird alles aktzeptiert.) oder auch 192.168.0.0/255.255.255.0
"
-d 127.0.0.1"
DESTINATION - gibt die Ziel-IP an, zu der das Paket geht, das vond er Regel betroffen sein soll. (Rest siehe bei Option -s)
"
-p tcp"
PROTOCOL - gibt den Protokollnamen an (tcp, udp und icmp sind möglich)
"
-j ACCEPT"
JUMP - sagt an was mit einem dem Paket geschehen soll, auf das die Regel trifft. möglich sind: ACCEPT DROP REJECT oder selbsterstellte Ketten wie zB. die oben mit "iptables -N sperre" erstellte Kette. Unten im Howto wirst du sehen wieso ich das erwähnt habe.. ;-)
Eines ist allen Scripts gemeinsam: Sie müssen nach jedem Neustart des Systems neu geladen werden. Dazu speichert man das Script als Startscript. Unter Debian habe ich es nach
/etc/init.d/routing kopiert und einen symlink von
/etc/rc2.d/S20routing darauf gesetzt, so dass es bei jedem Neustart geladen wird.
Das erste Script ist ein Beispiel für eine IPTables-Firewall auf einem Einzelrechner installiert - dies ist meistens nicht der Fall, aber sei hier trotzdem erwähnt, da es das Verständnis von regeln für das lokale System im Vergleich zu solchen für ein ganzes Subnetz schult.
Script 1
#! /bin/sh
iptables -F
iptables -F sperre
iptables -X sperre
iptables -N sperre
iptables -F sperre
iptables -A sperre -i lo -s 127.0.0.1/255.0.0.0 -j ACCEPT # Für Loopback wir immer alles erlaubt ausser von nicht 127.0.0.1
# acceptstuff #
###############
iptables -A sperre -p tcp --dport 21 -j ACCEPT # ftp akzeptieren
iptables -A sperre -p tcp --dport 4100:4115 -j ACCEPT # icq portrange
# Antworten zulassen #
######################
iptables -A sperre -m state --state ESTABLISHED,RELATED -j ACCEPT
# Alles andere abweisen (RFC-konform) #
#######################################
iptables -A sperre -p tcp -j REJECT --reject-with tcp-reset
iptables -A sperre -p udp -j REJECT --reject-with icmp-port-unreachable
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT # output immer annehmen (vorsicht vor Trojanern!)
# NAT #
#######
iptables -A POSTROUTING -t nat -o ppp0 -j MASQUERADE # was rausgeht wird maskiert
echo "Firewall started"
Soweit so gut - Das war ein einzelner Rechner mit ADSL-Anschluss ans Internet - jetzt derselbe Rechner nocheinmal - diesmal mit einem ganzen kleinen Klasse C Netzwerk dahinter. Die IPs sind 192.168.0.*.
Script 2
#! /bin/sh
echo "1" > /proc/sys/net/ipv4/ip_forward # Initialisierung des Forwardings
# Flushen, Löschen, Neuerstellung - nicht vergessen im Script! #
################################################################
iptables -F
iptables -F -t nat
iptables -F sperre
iptables -X sperre
iptables -N sperre
iptables -F sperre
# first contact #
#################
iptables -A sperre -i eth0 -s ! 192.168.0.0/255.255.255.0 -j DROP # Alles aus dem lan ohne passende IP wegwerfen
iptables -A sperre -i eth0 -j ACCEPT # Sonst alles von eth0 erlauben (Hier sollte man aufpassen, was man den Usern gewähren will und sich vor Trojanern schützen.)
iptables -A sperre -i lo -s 127.0.0.1/255.0.0.0 -j ACCEPT # Für Loopback wir immer alles erlaubt ausser von nicht 127.0.0.1
iptables -A sperre -i ppp0 -s 192.168.0.0/255.255.255.0 -j DROP # Alles aus dem Inet mit meinen IPs werwerfen
# acceptstuff #
###############
iptables -A sperre -p tcp --dport 21 -j ACCEPT # ftp erlauben
iptables -A sperre -p tcp --dport 4100:4115 -j ACCEPT # icq portrange erlauben
# Antworten zulassen #
######################
iptables -A sperre -m state --state ESTABLISHED,RELATED -j ACCEPT
# Alles andere abweisen (RFC-konform) #
# folgende Zeilen garantieren RFC-konforme Antworten. (Port geschlossen), aber Antworten sind Antworten. Jedes Paket kann Informationen beinhalten, also ist ein DROP an dieser Stelle sicherer, allerdings wird ein DROP von Portscannern als gefiltert erkannt und macht den rechner interessanter, REJECT, wie es unten angeführt ist, als geschlossen. Jeder möge selbst entscheiden..
#######################################
iptables -A sperre -p tcp -j REJECT --reject-with tcp-reset
iptables -A sperre -p udp -j REJECT --reject-with icmp-port-unreachable
# sperre aktivieren #
#####################
iptables -A INPUT -j sperre
iptables -A FORWARD -j sperre
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT # output immer annehmen (nochmal ein Trojanerhinweis...)
iptables -P OUTPUT ACCEPT -t nat
# NAT #
#######
iptables -A POSTROUTING -t nat -o ppp0 -j MASQUERADE # was rausgeht wird maskiert
iptables -A PREROUTING -t nat -i ppp0 -p tcp --dport 4100:4115 -j DNAT --to 192.168.0.2 # icq soll an einen anderen Rechner geleitet werden
iptables -A PREROUTING -t nat -i ppp0 -p tcp --dport 21 -j DNAT --to 192.168.0.2 # ftp genauso
echo "Firewall started"
Das obige Beispiel lässt sich ein wenig anpassen.. dann funktioniert es ganz gut. Wenn du was eigenes bastelst achte unbedingt darauf "
iptables -P INPUT DROP" zu machen und DANN die Dinge die rein dürfen zu erlauben und nicht andersrum. Was nicht erlaubt ist, ist verboten!
Für eingehendere Informationen guck mal auf:
http://netfilter.samba.org/documentation/HOWTO/de/packet-filtering-HOWTO-7.html
und auch ein "
man iptables" klärt so manches auf.
Einige der hier verwendeten Informationen stammen auch aus einem Artikel von Klaus Rechert aus dem Sonderheft 1/2004 ("Security Edition") des Linux Magazins.
Viel Erfolg beim Einrichten!
PS: Wenn ihr einen Router per ssh konfiguriert vergesst AUF KEINEN FALL entweder allen LAN-Verkehr zu erlauben oder ssh (Port 22) freizugeben.. sonst sperrt ihr euch aus..... Ich habs schon hinbekommen :P
Gruß, Tam