38.5Firewall mit iptables selbst gebaut

Minimale Client-Absicherung (IPv4 und IPv6)

Die meisten Rechner genießen zu Hause oder in einer Firma in lokalen IPv4-Netzwerken dank NAT eine gewisse Sicherheit. Damit ist es vorbei, wenn Sie unterwegs in einem öffentlichen WLAN E-Mails abrufen: Sie wissen nicht, wer sich sonst noch im Funknetz befindet!

Ein ähnliches Sicherheitsproblem haben Sie, wenn Sie (wie in Abschnitt 27.2, »Manuelle LAN- und WLAN-Konfiguration«, beschrieben) einen Tunnel-Dienst wie Gogo oder SixXs einrichten. Damit hat Ihr Rechner eine zusätzliche IPv6-Adresse. NAT spielt nun keine Rolle mehr: Weltweit kann nun jeder, der über eine IPv6-Verbindung verfügt, IP-Pakete zu Ihrem Rechner senden! Diese Datenpakete können z.B. dazu dienen, um einen SSH-Login zu versuchen oder um über Samba freigegebene Netzwerkverzeichnisse auszulesen.

Die folgende Mini-Firewall verbessert die Sicherheit in beiden Fällen ganz erheblich. Sie verbietet grundsätzlich jeden Datenverkehr, der nicht von Ihrem Rechner initiiert wird. Mit anderen Worten: Sie können z.B. via SSH einen externen Rechner administrieren, umgekehrt kann aber niemand auch nur versuchen, sich via SSH bei Ihnen einzuloggen. Analog funktioniert dieser Schutz auch für alle anderen Netzwerkdienste.

Das Beispiel wurde unter Ubuntu entwickelt und getestet. Wenn Sie eine andere Distribution verwenden, müssen Sie unbedingt vorher die distributionsspezifische Firewall deaktivieren bzw. unter Fedora das Paket firewalld deinstallieren!

Der erste Teil des Firewall-Scripts führt eine Art iptables-Reset durch. iptables -P stellt dann das Standardverhalten aller Filter auf ACCEPT. iptables -F löscht alle vorhandenen Regeln, wobei für die NAT-Tabelle ein eigenes Kommando erforderlich ist. iptables -X löscht alle benutzerdefinierten Regelketten. Analog werden all diese Kommandos auch für IPv6 ausgeführt. Netfilter erlaubt nun jeglichen IP-Verkehr.

#!/bin/bash # Mini-Firewall (Teil 1) IPT4=$(which iptables) IPT6=$(which ip6tables) # reset iptables for IPT in $IPT4 $IPT6; do $IPT -P INPUT ACCEPT $IPT -P OUTPUT ACCEPT $IPT -P FORWARD ACCEPT $IPT -F $IPT -X done

Damit IPv6-Funktionen zur Autokonfiguration funktionieren, ist es erforderlich, ICMPv6-Pakete passieren zu lassen. Dazu dienen die zwei abschließenden Kommandos im ersten Teil des Listings:

# Mini-Firewall (Teil 2): ICMPv6 zulassen $IPT6 -A INPUT -p ipv6-icmp -j ACCEPT $IPT6 -A FORWARD -p ipv6-icmp -j ACCEPT

Die folgenden Zeilen definieren eine neue Regelkette mit dem Namen wall. Sie stellt einen ebenso eleganten wie wirkungsvollen Schutz vor neuen Verbindungen von außen dar. Die erste wall-Regel besagt, dass alle Pakete akzeptiert werden, die zu einer bereits vorhandenen Verbindung gehören.

Die zweite Regel akzeptiert Pakete, die eine neue Verbindung initiieren, sofern die Verbindung nicht über die Internetschnittstelle hergestellt wird. Die Inversion wird syntaktisch durch das Ausrufezeichen vor der Option -i ausgedrückt. Im Klartext bedeutet die Regel, dass es beispielsweise möglich ist, aus dem lokalen Netz heraus eine HTTP-Kommunikation mit dem Rechner zu starten, nicht aber aus dem Internet heraus.

Die dritte Regel lautet: Alle Pakete, die nicht den vorigen Regeln entsprechen, werden abgewiesen. Diese letzte Regel entspricht also dem Motto: Alles verbieten, was nicht explizit erlaubt ist! Einem potenziellen Angreifer aus dem Internet wird es daher nicht gelingen, eine SSH-Session auch nur zu starten. Das Gleiche gilt natürlich auch für alle anderen Netzwerkdienste – HTTP, FTP, Telnet etc.

Die zwei abschließenden Kommandos des Scripts geben an, dass für alle Pakete, die die Input- oder Forward-Filter durchlaufen, die wall-Regeln zur Anwendung kommen:

# Mini-Firewall (Teil 3): wall-Regelkette für IPv4 INET=eth0 $IPT4 -N wall $IPT4 -A wall -m state --state ESTABLISHED,RELATED -j ACCEPT $IPT4 -A wall -m state --state NEW ! -i $INET -j ACCEPT $IPT4 -A wall -j DROP # die Regelkette für INPUT und FORWARD anwenden $IPT4 -A INPUT -j wall $IPT4 -A FORWARD -j wall

Der letzte Teil der Mini-Firewall definiert dieselbe wall-Regelkette für IPv6. Dabei müssen Sie beachten, dass bei Tunnelverbindungen eine andere Netzwerkschnittstelle aktiv ist: Während IPv4-Verkehr nach eth0 fließt, geht IPv6-Verkehr über die Tunnelschnittstelle, im folgenden Beispiel sixxs:

# Mini-Firewall (Teil 4): wall-Regelkette für IPv6 INET6=sixxs $IPT6 -N wall $IPT6 -A wall -m state --state ESTABLISHED,RELATED -j ACCEPT $IPT6 -A wall -m state --state NEW ! -i $INET6 -j ACCEPT $IPT6 -A wall -j DROP $IPT6 -A INPUT -j wall $IPT6 -A FORWARD -j wall

Internet-Gateway für lokales Netzwerk absichern (IPv4 und IPv6)

Das zweite Beispiel baut auf den obigen Ideen auf, ist aber schon etwas anspruchsvoller. Es geht darum, ein Gateway abzusichern, das anderen Rechnern im LAN Internetzugang gibt (siehe Kapitel 28, »Internet-Gateway«). Abbildung 38.1 zeigt die Ausgangssituation.

Die Aufgabe der Firewall besteht darin, gefährliche Ports nach außen hin ganz zu blockieren und bei den restlichen Ports eine Kommunikation nur dann zu erlauben, wenn die Kommunikation von innen initiiert wurde. Der Schutz gilt nun auch für alle IPv4- und IPv6-Clients im lokalen Netzwerk. Das Firewall-Script kümmert sich außerdem um die Aktivierung der Masquerading- und Forwarding-Funktionen.

Die Firewall besteht aus den beiden Script-Dateien myfirewall-start und myfirewall-stop. Die Grundeinstellungen der Firewall werden in der Konfigurationsdatei myfirewall gespeichert.

/etc/myfirewall/myfirewall-start (Firewall-Start) /etc/myfirewall/myfirewall-stop (Firewall-Stopp) /etc/default/myfirewall (Grundeinstellungen)

Basiskonfiguration (myfirewall)

Die Variable MFW_ACTIVE in /etc/default/myfirewall steuert, ob die Firewall während des Systemstarts aktiviert werden sollen. MFW_MASQ gibt an, ob Masquerading und Forwarding aktiviert werden sollen. Die restlichen Variablen geben die Schnittstellen und Adressen des lokalen Netzwerks bzw. der Internetverbindung an. eth0 und eth1 müssen Sie durch die Namen Ihrer Schnittstellen ersetzen, z.B. durch enp4s0 oder wlp2s0.

Sofern auf Ihrem Gateway eine Tunnel-Software läuft (z.B. aiccu für SixXs), um auch IPv6-Verkehr vom LAN in das Internet zu leiten, gibt die Variable MFW_INET6 die entsprechende Schnittstelle an. Wenn Ihr lokales Netz kein IPv6 nutzt, können Sie alle diesbezüglichen Einstellungen und Kommandos aus den Scripts streichen.

# Datei /etc/default/myfirewall # Firewall starten: yes/no MFW_ACTIVE=yes # Masquerading und Forwarding aktivieren: yes/no MFW_MASQ=yes # Lokales Netzwerk MFW_LAN=eth1 MFW_LAN_IP=192.168.0.0/24 # Schnittstelle zum Internet (IPv4 und IPv6) MFW_INET=eth0 MFW_INET6=sixxs

Firewall stoppen (myfirewall-stop)

Das Script myfirewall-stop stellt den iptables-Grundzustand her und deaktiviert die Firewall – wie in den ersten Zeilen der Mini-Firewall. Ergänzend dazu werden diesmal auch die nat-Regelketten zurückgesetzt.

#!/bin/bash # Datei /etc/myfirewall/myfirewall-stop # Konfigurationseinstellungen lesen . /etc/default/myfirewall IPT4=$(which iptables) IPT6=$(which ip6tables) SYS=$(which sysctl) # Firewall-Reset (IPv4 und IPv6) for IPT in $IPT4 $IPT6; do $IPT -P INPUT ACCEPT $IPT -P OUTPUT ACCEPT $IPT -P FORWARD ACCEPT $IPT -F $IPT -X done # NAT-Reset nur für IPv4 $IPT4 -F -t nat $IPT4 -P POSTROUTING ACCEPT -t nat $IPT4 -P PREROUTING ACCEPT -t nat $IPT4 -P OUTPUT ACCEPT -t nat # Forwarding stoppen $SYS -q -w net.ipv4.ip_forward=0 $SYS -q -w net.ipv6.conf.all.forwarding=0

Vergessen Sie nicht, die Script-Datei mit chmod u+x als ausführbar zu kennzeichnen!

Firewall starten (myfirewall-start)

Wesentlich interessanter ist naturgemäß myfirewall-start. Das Script beginnt damit, die Stopp-Regeln auszuführen. Das bewirkt gleichsam ein Reset des Netfilter-Systems. Alle weiteren iptables-Kommandos können sich somit darauf verlassen, dass vorher keine anderen Regeln definiert wurden.

Die ersten drei iptables-Kommandos lassen den Zugriff auf SSH-Server aus dem Internet zu. Diese Kommandos zeigen beispielhaft, wie Sie trotz Firewall einzelne Dienste nach außen zugänglich machen. Beachten Sie, dass das Absichern eines SSH-Servers im IPv6-Netz schwierig ist; sicherer ist es, SSH zumindest für IPv6 zu sperren.

#!/bin/bash # Datei /etc/myfirewall/myfirewall-start (Teil 1) # Konfigurationseinstellungen lesen . /etc/default/myfirewall IPT=$(which iptables) SYS=$(which sysctl) if [ $MFW_ACTIVE != "yes" ]; then echo "Firewall disabled in /etc/default/myfirewall" exit 0 fi # Reset aller Firewall-Regeln . /etc/myfirewall/myfirewall-stop # Zugriff auf den SSH-Server (Port 22) aus dem Internet erlauben $IPT4 -A INPUT -i $MFW_INET -p tcp --dport 22 -j ACCEPT $IPT6 -A INPUT -i $MFW_INET6 -p tcp --dport 22 -j ACCEPT $IPT6 -A FORWARD -i $MFW_INET6 -p tcp --dport 22 -j ACCEPT # ICMPv6 erlauben $IPT6 -A INPUT -p ipv6-icmp -j ACCEPT $IPT6 -A FORWARD -p ipv6-icmp -j ACCEPT

In der for-Schleife werden nun einige Ports gegenüber dem Internet vollständig blockiert. Sie können die Port-Liste bei Bedarf selbst ergänzen.

# Datei /etc/myfirewall/myfirewall-start (Teil 2) # einige Ports komplett sperren # 23 (telnet) # 69 (tftp) # 135 (Microsoft DCOM RPC) # 139 (NetBIOS/Samba/etc.) # 445 (CIFS-Dateisystem für Samba/SMB) # 631 (ipp/CUPS) # 1433 (Microsoft SQL Server) # 2049 (NFS) # 3306 (MySQL) # 5999-6003 (X-Displays) for PORT in 23 69 135 139 445 631 1433 2049 3306 \ 5999 6000 6001 6002 6003; do $IPT4 -A INPUT -i $MFW_INET -p tcp --dport $PORT -j DROP $IPT4 -A OUTPUT -o $MFW_INET -p tcp --dport $PORT -j DROP $IPT4 -A INPUT -i $MFW_INET -p udp --dport $PORT -j DROP $IPT4 -A OUTPUT -o $MFW_INET -p udp --dport $PORT -j DROP $IPT6 -A INPUT -i $MFW_INET -p tcp --dport $PORT -j DROP $IPT6 -A OUTPUT -o $MFW_INET -p tcp --dport $PORT -j DROP $IPT6 -A INPUT -i $MFW_INET -p udp --dport $PORT -j DROP $IPT6 -A OUTPUT -o $MFW_INET -p udp --dport $PORT -j DROP done

Die Idee der wall-Regelkette habe ich schon im Rahmen der Mini-Firewall beschrieben. Bei diesem größeren Beispiel kommt sie nur zur Anwendung, wenn nicht schon vorher eine der DROP- oder ACCEPT-Regeln zutraf. Die Reihenfolge der Regeln ist also beim Aufbau einer Firewall entscheidend!

# Datei /etc/myfirewall/myfirewall-start (Teil 3) # wall-Regelkette für IPv4 .. $IPT4 -N wall $IPT4 -A wall -m state --state ESTABLISHED,RELATED -j ACCEPT $IPT4 -A wall -m state --state NEW ! -i $MFW_INET -j ACCEPT $IPT4 -A wall -j DROP $IPT4 -A INPUT -j wall $IPT4 -A FORWARD -j wall # ... und für IPv6 $IPT6 -N wall $IPT6 -A wall -m state --state ESTABLISHED,RELATED -j ACCEPT $IPT6 -A wall -m state --state NEW ! -i $MFW_INET6 -j ACCEPT $IPT6 -A wall -j DROP $IPT6 -A INPUT -j wall $IPT6 -A FORWARD -j wall

Zu guter Letzt müssen auf einem Gateway das Masquerading und das Forwarding aktiviert werden (siehe Abschnitt 28.3, »Masquerading«):

# Datei /etc/myfirewall/myfirewall-start (Teil 4) if [ $MFW_MASQ = 'yes' ]; then $IPT4 -A POSTROUTING -t nat -o $MFW_INET -s $MFW_LAN_IP -j MASQUERADE $SYS -q -w net.ipv4.ip_forward=1 $SYS -q -w net.ipv6.conf.all.forwarding=1 fi

Init-V-Integration

Zum Start der Firewall bietet sich ein Init-V-Script an. Es funktioniert auf fast allen Distributionen, da sowohl Upstart als auch Systemd dazu kompatibel sind. Details des Scripts müssen Sie dennoch an die Besonderheiten der jeweiligen Distribution anpassen.

#!/bin/sh -e # eigenes Init-V-Script /etc/init.d/myfirewall ### BEGIN INIT INFO # Provides: firewall # Required-Start: networking # Required-Stop: # Default-Start: S # Short-Description: Start firewall and masquerading ### END INIT INFO # Grundfunktionen . /lib/lsb/init-functions # Funktionen für start, stop und restart case "$1" in start|restart) log_begin_msg "Starting firewall and masquerading ..." . /etc/myfirewall/myfirewall-start log_end_msg 0 ;; stop) log_begin_msg "Stopping firewall and masquerading ..." . /etc/myfirewall/myfirewall-stop log_end_msg 0 ;; status) /sbin/iptables -L -v -n ;; *) log_success_msg "Usage: xxx {start|stop|restart|status}" exit 1 ;; esac exit 0

Damit dieses Script beim Systemstart automatisch ausgeführt wird, richten Sie unter Debian und Ubuntu den folgenden Link ein:

root# cd /etc/rcS.d root# ln -s ../init.d/myfirewall S41myfirewall