Simple Firewall mittels IPtables

Ein Server ohne Firewall – kann man mal machen, aber dann ist es halt …. 😉

Zugegeben, der Grundstock dieses Scripts stammt nicht aus meiner Feder. Ich habe es vor Jahren mal irgendwo gefunden und dann immer wieder angepasst mittlerweile schlummert bei mir auf nahezu jedem Server das folgende Script in einem «script-Verzeichnis» als iptables.sh:

#!/bin/bash

### BEGIN INIT INFO
# Provides:          iptables-firewall
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: iptables-firewall
# Description:       iptables-firewall
### END INIT INFO

#Ports: Hier eintragen welche Ports geöffnet werden sollen
SERVICES_UDP=""                 #freigegebene UDP-Ports
SERVICES_TCP="22 80 443"        #freigegebene TCP-Ports (Hier sshd und http/https)

#Alle vorhandenen Regeln löschen
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X
iptables -t nat -X
iptables -t mangle -X

#Grundregeln
iptables -P OUTPUT  ACCEPT
iptables -P INPUT   DROP
iptables -P FORWARD DROP

#Sicherheit
iptables -N other_packets                                                               #Tabelle "other_packets" erzeugen
iptables -A other_packets -p ALL -m state --state INVALID -j DROP                       #Kaputte Pakete verwerfen
iptables -A other_packets -p icmp -m limit --limit 1/s -j ACCEPT                        #ICMP auf max. 1 Paket/Sekunde limitieren
iptables -A other_packets -p ALL -j RETURN                                              #Tabelle "other_packets" verlassen

iptables -N service_sec                                                                 #Tabelle "services_sec" erzeugen
iptables -A service_sec -p tcp --syn -m limit --limit 2/s -j ACCEPT                     #SYN-Flood Attacken
iptables -A service_sec -p tcp ! --syn -m state --state NEW -j DROP                     #TCP-SYN-Pakete ohne Status NEW verwerfen
iptables -A service_sec -p tcp --tcp-flags ALL NONE -m limit --limit 1/h -j ACCEPT      #Portscanner ausschalten
iptables -A service_sec -p tcp --tcp-flags ALL ALL -m limit --limit 1/h -j ACCEPT       #Portscanner ausschalten
iptables -A service_sec -p ALL -j RETURN                                                #Tabelle "services" verlassen

iptables -N reject_packets                                                                                                                      #Tabelle "reject_packets" erzeugen
iptables -A reject_packets -p tcp -j REJECT --reject-with tcp-reset                     #TCP Pakete(Protokoll) zurückweisen
iptables -A reject_packets -p udp -j REJECT --reject-with icmp-port-unreachable         #UDP Pakete(Protokoll) zurückweisen
iptables -A reject_packets -p icmp -j REJECT --reject-with icmp-host-unreachable        #ICMP Pakete(Protokoll) zurückweisen (bei mehr als 1Paket/Sekunde [s.o.])
iptables -A reject_packets -j REJECT --reject-with icmp-proto-unreachable               #Alle anderen Pakete(Protokolle) zurückweisen
iptables -A reject_packets -p ALL -j RETURN                                             #Tabelle "reject_packets" verlassen

#Dienste
iptables -N services                                                                    #Tabelle für die Dienste erzeugen
for port in $SERVICES_TCP ; do                                                          #Für jeden TCP Port (oben definiert) folgendes tun:
       iptables -A services -p tcp --dport $port -j service_sec                         #Bei Verbindungen auf TCP Port "$port in die Tabelle "services_sec" springen
       iptables -A services -p tcp --dport $port -j ACCEPT                              #Bei Verbindungen auf TCP Port "$port Verbindung zulassen
done
for port in $SERVICES_UDP ; do                                                          #Für jeden UDP Port (oben definiert) folgendes tun:
       iptables -A services -p udp --dport $port -j service_sec                         #Bei Verbindungen auf UDP Port "$port" in die Tabelle "services_sec" springen
       iptables -A services -p udp --dport $port -j ACCEPT                              #Bei Verbindungen auf UDP Port "$port Verbindung zulassen
done
iptables -A services -p ALL -j RETURN                                                   #Tabelle "services" verlassen

#INPUT
iptables -A INPUT -p ALL -i lo -j ACCEPT                                                #Alle Pakete vom Loopback Interface zulassen
iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT                 #Bereits vorhandene Verbindungen zulassen
iptables -A INPUT -p ALL -j other_packets                                               #In die Tabelle "other_packets" springen
iptables -A INPUT -p ALL -j services                                                    #In die Tabelle "services" gehen
iptables -A INPUT -p ALL -m limit --limit 10/s -j reject_packets                        #Nicht erlaubte Pakete zurückweisen, max 10Pakete/Sekunde (Tabelle "reject_Packets")
iptables -A INPUT -p ALL -j DROP                                                        #Alles andere verwerfen

#OUTPUT:
iptables -A OUTPUT -p ALL -j ACCEPT


Ich habe (schon damals) versucht, es mit Kommentaren einigermassen verständlich zu machen. Versucht 😉

Damit das Script beim Starten direkt ausgeführt wird, muss es noch nach init.d verlinkt werden (oder direkt dort abgespeichert) und dann noch als Service hinzugefügt werden. An dieser Stelle aber erstmal ein dickes

Achtung!!

Ab dem Punkt, wo die Datei verlinkt ist und als Service eingetragen ist, wird sie bei jedem Start ausgeführt. Sprich: Wenn ihr wichtige Ports darin vergesst (wie z.B. SSH bei einem remote-Server), schiesst ihr euch selbst in’s Knie und sperrt euch aus. Daher vor dem Eintrag am Besten das Script direkt ausführen und testen. Wenn ihr danach nicht mehr auf den Server kommt: Reboot und neuer Versuch.

Wenn alles eingerichtet ist, dann noch folgende beiden Befehle auf der Konsole absetzen und schon kommt die Firewall nach jedem Neustart automatisch:

ln -s /pfad/zu/iptables.sh /etc/init.d/iptables
update-rc.d iptables defaults

Danach neustarten und mittels

iptables -L

Testen, ob das Script gezogen hat. Die Ausgabe sollte wie folgt aussehen:

Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
other_packets  all  --  anywhere             anywhere
services   all  --  anywhere             anywhere
reject_packets  all  --  anywhere             anywhere             limit: avg 10/sec burst 5
DROP       all  --  anywhere             anywhere

Chain FORWARD (policy DROP)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere

Chain other_packets (1 references)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere             state INVALID
ACCEPT     icmp --  anywhere             anywhere             limit: avg 1/sec burst 5
RETURN     all  --  anywhere             anywhere

Chain reject_packets (1 references)
target     prot opt source               destination
REJECT     tcp  --  anywhere             anywhere             reject-with tcp-reset
REJECT     udp  --  anywhere             anywhere             reject-with icmp-port-unreachable
REJECT     icmp --  anywhere             anywhere             reject-with icmp-host-unreachable
REJECT     all  --  anywhere             anywhere             reject-with icmp-proto-unreachable
RETURN     all  --  anywhere             anywhere

Chain service_sec (3 references)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,ACK/SYN limit: avg 2/sec burst 5
DROP       tcp  --  anywhere             anywhere             tcp flags:!FIN,SYN,RST,ACK/SYN state NEW
ACCEPT     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE limit: avg 1/hour burst 5
ACCEPT     tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,PSH,ACK,URG/FIN,SYN,RST,PSH,ACK,URG limit: avg 1/hour burst 5
RETURN     all  --  anywhere             anywhere

Chain services (1 references)
target     prot opt source               destination
service_sec  tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
service_sec  tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
service_sec  tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
RETURN     all  --  anywhere             anywhere

Noch ein kleiner Hinweis: iptables arbeitet alles nacheinander ab. Wenn also oben erstmal alles verboten wird und dann nach und nach dinge wieder erlaubt werden, ist das so in Ordnung.

Weitere nützliche Informationen zu IPtables findet ihr hier.

Dieser Beitrag wurde unter Debian, Linux, Server veröffentlicht. Setzen Sie ein Lesezeichen auf den Permalink.

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert