# ====================================================================== # Teil 1: Variablendeklaration # ====================================================================== set IPTABLES = /sbin/iptables # ---------------------------------------------------------------------- # spezielle Ports set p_high = 1024:65535 # unprivilegierte Ports set p_ssh = 500:1023 # gemeinsame SSH Quell Ports # ---------------------------------------------------------------------- # Interfaces set EXT = ppp0 # Hier DSL durch pppd erzeugtes Geraet set INT = eth0 set IF = ( $EXT $INT ) # ---------------------------------------------------------------------- # IP Hosts set NS = ( 192.168.0.1 ) set loghost = 192.168.0.1 set INTERN = 192.168.0.0/255.255.255.0 # Internes Netzwerk set FIREWALL = 192.168.0.1Hier passiert zunächst nicht viel. Wir deklarieren hier im Prinzip Variablen, damit wir im Verlauf des Skriptes nicht mit wilden IP-Nummern und Ports hantieren müssen. Ein Wort zu den Variablen p_high und p_ssh. Die unprivilegierten Ports p_high sind Quell, bzw. Source Ports, von denen aus manche Dämonen, oder andere Serverdienste, einen Verbindungsaufbau instantiieren möchten. Beispielsweise eine Nameserveranfrage. Startet man nslookup, versucht der Client auf den Server und dessen Port 53 ein Verbindung anzufordern. Der Client selbst muß dies aber nicht zwingen vom Port 53 tun. Er kann auch als Quellport 32129 (oder einen anderen) verwenden. Um nun solche Anfragen zu erlauben, müssen wir bestimmte Portbereiche, von denen Userspace Programme Anfragen starten, als Quellport erlauben. Dazu gleich ein wenig später. Kommen wir zur Grundabsicherung. Im nächsten Teil des Skriptes folgt:
# ====================================================================== # Teil 2: Grundkonfiguration absichern # ====================================================================== # dynamische Kernelparameter setzen echo "0" > /proc/sys/net/ipv4/ip_forward # erstmal abschalten echo "1" > /proc/sys/net/ipv4/tcp_syncookies echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses #echo "5" > /proc/sys/net/ipv4/icmp_destunreach_rate #echo "5" > /proc/sys/net/ipv4/icmp_echoreply_rate #echo "5" > /proc/sys/net/ipv4/icmp_paramprob_rate #echo "10" > /proc/sys/net/ipv4/icmp_timeexceed_rate foreach if ( $IF ) echo "1" > /proc/sys/net/ipv4/conf/$if/rp_filter echo "0" > /proc/sys/net/ipv4/conf/$if/accept_redirects echo "0" > /proc/sys/net/ipv4/conf/$if/accept_source_route echo "0" > /proc/sys/net/ipv4/conf/$if/bootp_relay echo "1" > /proc/sys/net/ipv4/conf/$if/log_martians end # ----------------------------------------------------------------------- # Default Policy und flush $IPTABLES -P INPUT DROP $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT DROP $IPTABLES -F # flush aller chains (Tabelle filter) $IPTABLES -t nat -F # flush aller chains (Tabelle nat) $IPTABLES -X # delete all userdefined chains # (Tabelle filter) # ---------------------------------------------------------------------- # lokale Prozesse $IPTABLES -A OUTPUT -o lo -j ACCEPT $IPTABLES -A INPUT -i lo -j ACCEPTAm Anfang des Teil 2, wird zunächst ip_forward abgeschaltet, tcp_syncookies, icmp_echo_ignore_broadcasts, icmp_ignore_bogus_error_responses eingeschaltet. Ip_forward schalten wir erst wieder ein, sobald alle wichtigen Regeln gesetzt wurden. Danach wird erst einmal der gesamte Rechner komplett geschützt, indem man alles DROP't (versperrt, abweisst). Schließlich werden auch die bisherigen im Kernel bereits gesetzten Standardregeln sicherheitshalber gelöscht. Damit haben wir zunächst erreicht daß niemand mehr auf diesen Rechner von außen zugreifen kann, auch wir nicht. Um jedoch lokalen Diensten den Zugang zu Server zu erlauben, definieren wir wie unter lokale Prozessezu sehen, die Regeln für die lokalen Dienste. Man erkennt hier auch die Syntax von iptables sehr gut. Allgemein lautet sie:
# ---------------------------------------------------------------------- # ausgehende Pakete bei bereits aufgebauter Verbindung # # Damit BIND nicht aufzuloesende Pakete weiterleiten kann muss noch ein NEW # bei der OUTPUT Chain bei state hinzugefuegt werden. $IPTABLES -A OUTPUT \ -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -i $INT -o $EXT \ -m state --state ESTABLISHED,RELATED -j ACCEPTDurch das Hinzufügen von NEW vor ESTABLISHED, wird erreicht, das wenn BIND eine neue Verbindung zu anderen Nameservern im Internet aufbaut, diese Verbindung von der Firewall nicht verhindert wird. Sonst scheitern sämtliche nicht aufzulösenden Namen an der Firewall.
# ---------------------------------------------------------------------- # Rueckkanal: eingehende Pakete zu einer bestehenden Verbindung # # Hinweis: der sichere Eintrag ist: # # $IPTABLES -A INPUT -m state --state NEW,INVALID -j my_drop # # Da aber DNS-Anfragen von Clients bei state ein NEW benoetigen, muessen # wir das NEW entfernen! - damit der hier lokal installierte BIND-Server # funktioniert! Des Weiteren geht auch ssh schneller, da die NEW Anfragen # nicht mehr gedropt werden $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A INPUT -m state --state INVALID -j my_dropMit dem Hinweis oben ist folgendes gemeint - Sollte man die auskommentierte Regel setzen, wehrt die Firewall alles ab, was einen Verbindungsaufbau zur Firewall (neue Verbindung NEW) versucht. Von außen, dem Internet ist das auch O.K. - doch leider blockt sie auch alle möglichen neuen Verbindungen von Innen ab. Genau dort ist das Problem. Startet man beispielsweise Netscape und versucht eine Internetadresse in den Browser einzugeben, wird eine Nameserveranfrage gestartet, diese jedoch von unserer Firewall geblockt. Dementsprechend lockern wir hier den Gürtel hier ein wenig und geben mit der nächsten Regel explizit an, das nur die Pakete von außen (deshalb -o ppp0), die eine Neue (NEW) Verbindung aufbauen möchten, geblockt werden.
# Um diese eben erwaehnte Sicherheit wiederherzustellen entweder: $IPTABLES -A INPUT -i $EXT -m state --state NEW,INVALID -j my_drop $IPTABLES -A FORWARD -i $EXT -o $INT \ -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -i $EXT -o $INT \ -m state --state NEW,INVALID -j my_drop...
# ---------------------------------------------------------------------- # DNS $IPTABLES -A INPUT -i $INT -s $INTERN \ -m state --state NEW \ -p UDP --sport $p_high -d $NS --dport domain \ -j ACCEPT $IPTABLES -A INPUT -i $INT -s $INTERN \ -m state --state NEW \ -p TCP --sport $p_high -d $NS --dport domain \ -j ACCEPT $IPTABLES -A OUTPUT -o $EXT -s $FIREWALL \ -m state --state NEW,ESTABLISHED,RELATED \ -p UDP --sport domain --dport domain \ -j ACCEPT $IPTABLES -A OUTPUT -o $EXT -s $FIREWALL \ -m state --state NEW,ESTABLISHED,RELATED \ -p TCP --sport domain --dport domain \ -j ACCEPTDie letzten vier Regeln definieren den Umgang mit Nameserveranfragen. Die beiden INPUT-Chains (einmal UDP und dann TCP) erlauben die Anfragen aus dem internen Netz an unseren Nameserver, die beiden OUTPUT-Chains das unser Nameserver die Anfragen, sofern er sie nicht selbst beantworten kann, weiterleiten darf. Nach einer kleinen Einarbeitung mit IPTABLES dürfte nun das folgende Skript kein Problem mehr sein.
Sven Alisch 2005-08-28