Eine Raspberry wird gerne eingesetzt um irgendwelche lokalen Serverdienste aus dem Internet zugreifbar zu machen. Dazu gehört z.B. ein Owncloud Server, ein HTTP Server oder ein Seafile Server.

Der richtige Ansatz ist den Server nur per VPN zugreifbar zu machen. Wenn man aber den Server eine größeren Allgemeinheit zur Verfügung stellen will und ein VPN deshalb ausfällt bleibt einem kaum eine andere Möglichgkeit, als den Server direkt aus dem Internet zugreifbar zu machen. Richtigerweise stellt man die Pi dann in eine DMZ zu Hause, aber die hat kaum jemand. Aber wenigstens sollte man seine Pi im lokalen Netz soweit wie möglich mit einer Firewall vor unerwünschten Besuchern schützen. Wenn ein Angreifer es allerdings schafft root Rechte zu erhalten ist der Firewallschutz aber schnell ausgeschaltet. Deshalb ist es sehr wichtig regelmäßig Software Udates vorzunehmen und den root Zugriff entsprechend gut zu schützen (Siehe auch hier - Wie einen sseh Server vor Angriffen aus dem Internet sichern)

Der folgende Beitrag beschreibt wie man eine Firewall mit iptables konfigurieren muss um seine lokale Pi netzwerkmässig vor Zugriffen aus dem Internet zu sichern und zu verhindern, dass jemand von der Pi ins lokale Netz zugreifen kann.

 


Wichtig: All diese Netzwerkmassnahmen bieten aber nur einen zusätzlichen Schutz für die Pi. Es muss unbedingt immer sichergestellt sein, dass das Betriebssystem der Pi immer alle aktuellen Sicherheitsupdates hat sowie auch Anwendungen - speziell die Anwendungen, die ihre Serverdienste im Internet anbieten. Damit verhindert man, dass ein Angreifer aus dem Internet die Pi übernimmt und von ihr Unfug im Internet anstellt sowie auf das lokale Netz zugreift. Man muss also durch aktuelle Software unbedingt verhindern, dass ein Angreiffer root Rechte erhält, denn ansonsten kann er die Firewall leicht ausschalten. Der richtige Ansatz wäre eine DMZ im lokalen Netz einzurichten, aber normale Homerouter bieten diese Möglichkeit leider nicht.

Die folgende Anleitung beschreibt, wie man einen lokalen Seafile Server mit einer Firewall absichert. Natürlich lässt sich jeder andere Serverdienst ähnlich absichern. Es sind nur die zu sichernden Ports zu ändern sowie die IP Adresse des lokalen Routers sowie des lokalen Netzes.

Das lokale Netz hat in der folgenden Konfiguration die folgenden Kennwerte:

1) Gateway (Router = Fritz 7390): 192.168.0.1

2) Lokales Netz: 192.168.0.0/255.255.255.0

 

Der Server wird wie folgt gesichert:

1) Es werden alle Zugriffe vom Server ins lokale Netz wie in das über den Router erreichbare Internet geblockt.

2) Es sind nur bestimmte Ports (Im Beispiel die Seafile Ports) aus dem Internet erreichbar

3) Jeder Client aus dem lokale Netz kann auf ssh auf dem Server zugreifen.

4) Ungültige Zugriffsversuche die dem TCP/IP Netzwerkprotokoll nicht gehorchen werden geblockt.

 

Folgende Schritte sind notwendig um die Firewall einzurichten im Betriebssystem raspbian:

1) Erstellen einer firewall Datei /etc/network/iptables

2) Erstellen einer Datei /etc/network/if-pre-up.d/firewall mit folgendem Inhalt um die Firewall nach einem Systemstart zu aktivieren

#!/bin/sh
/sbin/iptables-restore < /etc/network/iptables

Der Seafile Server benutzt die tcp Ports 8001, 8082, 10001 und 12001. Mein lokales Netz ist 192.168.0.0/24 und der Router hat die IP 192.168.0.1. Die jeweiligen Werte im folgenden Beispiel müssen dann den lokalen Gegebenheiten angepasst werden.

Deshalb sieht die iptables Datei wie folgt aus. Kommentare in der Datei beschreiben genau die Wirkung einer Zeile.

# Generated by iptables-save v1.4.14 on Tue Oct 28 21:05:48 2014
*filter
# default is drop all input
:INPUT DROP [103:11216]
:FORWARD DROP [0:0]
# default is to drop all output
:OUTPUT DROP [92:8720]

# logger
-N LOGNDROP  
-F LOGNDROP
-A LOGNDROP -j DROP
-A LOGNDROP -j LOG --log-prefix "LOGNDROP: "

# accept all local
-A INPUT -i lo -j ACCEPT

# accept all established sessions
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# drop requests in INVALID state
-A INPUT -m state --state INVALID -j DROP

# DROP INVALID SYN PACKETS
-A INPUT -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j LOGNDROP
-A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOGNDROP
-A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j LOGNDROP

# MAKE SURE NEW INCOMING TCP CONNECTIONS ARE SYN PACKETS; OTHERWISE WE NEED TO DROP THEM
-A INPUT -p tcp ! --syn -m state --state NEW -j LOGNDROP

# drop udp
-A INPUT -p udp -j DROP

# DROP PACKETS WITH INCOMING FRAGMENTS. THIS ATTACK RESULT INTO LINUX SERVER PANIC SUCH DATA LOSS
-A INPUT -f -j LOGNDROP

# DROP INCOMING MALFORMED XMAS PACKETS
-A INPUT -p tcp --tcp-flags ALL ALL -j LOGNDROP

# DROP INCOMING MALFORMED NULL PACKETS
-A INPUT -p tcp --tcp-flags ALL NONE -j LOGNDROP

# accept all requests for seafile ports
-A INPUT -p tcp -m multiport --dports 8001,8082,10001,12001 -m state --state NEW -j ACCEPT

# accept ssh request from local network
-A INPUT -s 192.168.0.0/24 -p tcp --dport 22 -j ACCEPT

# accept local broadcasts
-A INPUT -s 192.168.0.0/24 -d 192.168.0.255 -j ACCEPT
-A INPUT -d 255.255.255.255 -j ACCEPT

# accept multicasts
-A INPUT -d 224.0.0.1/32 -j ACCEPT

# accept pings from local network
-A INPUT -s 192.168.0.0/24 -p icmp -m icmp --icmp-type 8 -j ACCEPT

# drop pings otherwise (no logging please)
-A INPUT -p icmp -m icmp --icmp-type 8 -j LOG --log-prefix "INPUT:DROP:PING" --log-level 6

# drop 7390 pings from fritz
-A INPUT -s 192.168.0.1/32 -p tcp --dport 14013 -j DROP

# log dropped request
-A INPUT -j LOG --log-prefix "INPUT:DROP:" --log-level 6

# DROP INVALID SYN PACKETS
-A OUTPUT -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j LOGNDROP
-A OUTPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOGNDROP
-A OUTPUT -p tcp --tcp-flags SYN,RST SYN,RST -j LOGNDROP

# DROP PACKETS WITH OUTGOING FRAGMENTS. THIS ATTACK RESULT INTO LINUX SERVER PANIC SUCH DATA LOSS
-A OUTPUT -f -j LOGNDROP

# DROP OUTGOING MALFORMED XMAS PACKETS
-A OUTPUT -p tcp --tcp-flags ALL ALL -j LOGNDROP

# DROP OUTGOING MALFORMED NULL PACKETS
-A OUTPUT -p tcp --tcp-flags ALL NONE -j LOGNDROP

# accept established requests of seafile
-A OUTPUT -p tcp -m multiport --sports 8001,8082,10001,12001 -m state --state RELATED,ESTABLISHED -j ACCEPT

# accept established ssh connections from local network
-A OUTPUT -d 192.168.0.0/24 -p tcp --sport 22 -m state --state RELATED,ESTABLISHED -j ACCEPT

# accept output to send email
-A OUTPUT -p tcp --dport 587 -j ACCEPT

# accept local
-A OUTPUT -o lo -j ACCEPT

# accept all stuff directed to router
-A OUTPUT -d 192.168.0.1 -j ACCEPT

# allow ping replies
-A OUTPUT -d 192.168.0.0/24 -p icmp -m icmp --icmp-type 0 -j ACCEPT

# log dropped requests
-A OUTPUT -j LOG --log-prefix "OUTPUT:DROP:" --log-level 6
COMMIT

Warnung: Nach der Aktivierung der Firewall kann man nur zur Administration nur noch per ssh aus dem lokalen Netz oder einem lokal angeschlossenem Bildschirm und Tastatur auf die Pi zugreifen. Auch sind keine Updates oder Installationen von fehlenden Paketen mehr möglich.

Ein Update kann und sollte regelmäßig wir folgt durchgeführt werden:

sudo iptables -I OUTPUT -j ACCEPT       # erlaube download vom Internet 
sudo apt-get update
sudo apt-get upgrade
sudo iptables -D OUTPUT -j ACCEPT # blockiere jeglichen Zugriff auf das Internet wieder

Gibt es Verbindungsprobleme nach der Aktivierung der Firewall kann man mit dem folgenden Befehl herausfinden, warum ein Verbindungsversuch fehlschlug. Natürlich kann man damit auch kontrollieren, wer unberechtig versucht hat, Zugriff zu bekommen.

less +F /var/log/messages

Die Meldungen schreiben genau warum ein Zugriffsversuch fehlschlug.