Skip to content

Spezifikation von Firewallregeln - do's and dont's

Wenn eine Applikation über das Netz kommuniziert, funktioniert sie natürlich nur dann, wenn das Netz zwischen den beteiligten Maschinen diese Kommunikation auch durchleitet. Das ist im Internet üblicherweise der Fall; beim Übergang zwischen privaten Netzen und dem Internet in aller Regel nicht: Dort ist eine Firewall im Einsatz, die üblicherweise nach der Deny-all-Strategie alle Kommunikation blockiert, die nicht explizit freigegeben ist.

Auf diese Weise wird man im allgemeinen für eine neue Applikation eine Anpassung an der Firewall vornehmen müssen - es sei denn, die Applikation gibt sich Mühe, wie ein Dienst auszusehen, der üblicherweise freigegeben ist. Das tun zunehmend viele Applikationen und geben sich durch Benutzung von http als Transportprotokoll als Webclient und Webserver aus, was in vielen Firewalls direkt freigegeben ist. Doch dies ist Stoff für einen anderen Artikel.

In diesem Artikel möchte ich davon schreiben, wie die Spezifikation aussehen soll, damit der Firewalladmin auch weiß, was er für eine neue Applikation in seiner Firewall freischalten soll. In vielen Dokumentationen über (freie oder kommerzielle) Software findet man Listen von Ports, die mehr oder weniger vollständig und mehr oder weniger korrekt sind. Leider trifft in den meisten Fällen das "weniger" zu.

Doch zunächst ein paar Grundlagen zum Thema TCP/IP. Damit man in der Firewall nicht zu viel freigeben muss, sollten die notwendigen Kommunikationsbeziehungen möglichst eng beschrieben sein. Eine TCP/IP-Kommunikationsbeziehung fast aller Mainstreamprotokolle beschreibt ein Fünftupel, bestehend aus Source-IP, Destination-IP, Protokoll, Source-Port und Destination-Port.

Wenn ein Client C mit einem Server S sprechen möchte, dann ist das Protokoll, das er dafür benutzen möchte, in der Applikation festgelegt. TCP wird für Datenübertragung benutzt, bei der man sich darauf verlassen möchte, dass die Daten bei ihrer Ankunft am Ziel korrekt und vollständig sind, und bereit ist, dafür erhöhten Netzaufwand und unregelmäßige Übertragungszeiten in kauf zu nehmen. UDP benutzt man üblicherweise, wenn es sich nur um winzige Datenmengen (z.B. DNS-Anfragen und ihre Antworten) handelt oder es eher darauf ankommt, dass Daten entweder gar nicht oder halbwegs zeitlich passend ankommen (Streaming, Telefonie etc).

In beiden Fällen würfelt sich der Client normalerweise einen seiner freien Ports aus und benutzt diesen als Source-Port. Der Destination-Port ist meist mit der Applikation festgelegt und bestimmt auf der Seite des Empfängers den Prozess, bei dem das Paket abgeliefert werden soll. In der Programmierung funktioniert das so, dass der Serverprozess sich an den von ihm gewünschten Port bindet, ihn sozusagen "abhört" (im englischen nennt man das passender "listen on the port") und alle dorthin gesendeten Daten empfangen kann.

So hat eine DNS-Anfrage üblicherweise das Protokoll UDP (Protokollnummer 17), die Destination-IP des Nameservers und den Destination-Port 53. Der Server dreht bei seiner Antwort das Tupel um und sendet seine Antwort mit Source-Port 53 mit der IP des Clients als Destination-IP und der vom Client als seinen Source-Port gewählten Portnummer als Destination-Port. Das sieht "auf dem Kabel" in etwa so aus:

01: proto=UDP srcip=192.168.218.21 srcport=49221 dstip=206.251.36.94 dstport=53
02: proto=UDP srcip=206.251.36.94 srcport=53 dstip=192.168.218.21 dstport=49221
Hier hat sich der Client also den Port 49221 gewürfelt. Die Antwort des Servers kommt bei der Client-Applikation an, weil sie an den Port 49221 geschickt wurde - der Client kann also die Antwort anhand des Destination-Ports des Antwortpaketes der Frage zuordnen.

Bei TCP (Protokollnummer 6) ist's im Prinzip dasselbe, nur dass schon der Verbindungsaufbau (also bevor überhaupt ein Bit Nutzdaten geflossen sind) aus drei Paketen (dem sogenannten Dreiwegehandshake) besteht. Hier dasselbe für TCP und eine kurze http-Anfrage:

01: proto=TCP flags=SYN srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
02: proto=TCP flags=SYN,ACK srcip=81.169.179.176 srcport=80 dstip=192.168.218.21 dstport=37734
03: proto=TCP flags=ACK srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
04: proto=TCP flags= srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
05: proto=TCP flags= srcip=81.169.179.176 srcport=80 dstip=192.168.218.21 dstport=37734
06: proto=TCP flags= srcip=81.169.179.176 srcport=80 dstip=192.168.218.21 dstport=37734
07: proto=TCP flags= srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
08: proto=TCP flags=FIN srcip=81.169.179.176 srcport=80 dstip=192.168.218.21 dstport=37734
09: proto=TCP flags= srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
10: proto=TCP flags=FIN srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
11: proto=TCP flags= srcip=81.169.179.176 srcport=80 dstip=192.168.218.21 dstport=37734
Das bedarf dann doch einer kleinen Erklärung: Die Pakete 01 bis 03 sind der Dreiwegehandshake für den Verbindungsaufbau (SYN, SYN/ACK, ACK). In Paket 04 übermittelt der Client seinen http-Request, der in Paket 05 vom Server quittiert wird. Paket 06 ist die (in ein Paket passende) Antwort; Paket 07 die dazu gehörende Quittung. Da der Server keine weiteren Daten zu übermitteln hat, signalisiert er in Paket 08 den Wunsch des Verbindungsabbaus (FIN). Paket 09 ist die Quittung dafür; die Pakete 10 und 11 sind der Verbindungsabbau seitens des Clients und die dazu passende Quittung.

Abgesehen von den oben gezeigten Standardfällen gibt es noch einen ganzen Haufen von Sonderfällen. So hat ESP als IP-Protokoll keine Portnummern, so dass ein Paket einer ESP-Verbindung nur durch das Tripel Source-IP, Destination-IP, Protokollnummer 50 (ESP) klassifiziert werden kann. In einigen wenigen Protokollen spielt die Absenderportnummer eine Rolle; und wieder andere wenige Protokolle benutzen TCP UND UDP, dies aber auf derselben Portnummer. Und dann gibt es natürlich "kranke, firewallfeindliche" Protokolle wie ftp, SIP, nfs, amanda, RPC (inklusive MS-RPC), bei denen die Portnummern für den "eigentlichen" Dienst beidseitig erst durch eine Unterhaltung der beteiligten Systeme durch eine Steuerverbindung auf einem wohldefinierten Port ermittelt werden.

Wir sehen auch, dass im allgemeinen die Kommunikation zwischen zwei Systemen nahezu immer bidirektional stattfindet. Nur in ganz wenigen Sonderfällen (von denen mir gerade partout keiner einfallen möchte) versendet die eine Seite ein Paket, ohne sich jemals für eine Antwort oder Quittung zu interessieren. Glücklicherweise braucht man sich darum in der Regel heutzutage bei halbwegs aktuellen Firewalls nicht mehr zu kümmern: Es reicht, wenn man für eine erwünschte Kommunikationsbeziehung das jeweils erste Paket erlaubt; die direkt oder indirekt dazu gehörenden Pakete werden von der Firewall automatisch als solche erkannt und automatisch durchgelassen. Das trifft meist auf die direkten Antwortpakete zu, aber bei besseren Systemen auch auf kompliziertere Fälle wie den unabhängigen Datenkanal bei "kranken" Protokollen wie ftp oder zur Verbindung gehörende ICMP-Fehler wie "host unreachable" oder "fragmentation needed".

Für die beiden oben zitierten Paketdumps reichen also zwei Regeln:

proto=UDP srcip=192.168.218.21 srcport=49221 dstip=206.251.36.94 dstport=53
proto=TCP flags=SYN srcip=192.168.218.21 srcport=37734 dstip=81.169.179.176 dstport=80
Halt, stop. Da ist noch was zu viel: Der Source-Port wird vom Client jeweils neu ausgewürfelt; wir dürfen die Firewallregeln also nicht ganz so eng fassen, wenn der Dienst auch beim zweiten Zugriffsversuch noch funktionieren soll:
proto=UDP srcip=192.168.218.21 dstip=206.251.36.94 dstport=53
proto=TCP flags=SYN srcip=192.168.218.21 dstip=81.169.179.176 dstport=80
Wie wir alle wissen, benutzt DNS im Normalfall UDP, fällt aber bei manchen Fehlern auf das (langsamere, aufwändigere) TCP zurück - beispielsweise wenn die Antwort nicht mehr in ein Antwortpaket passt. Also braucht's noch eine dritte Regel, die den DNS-Sonderfall abdeckt:
proto=TCP flags=SYN srcip=192.168.218.21 dstip=206.251.36.94 dstport=53
Bei TCP ist es zweckmäßig, nur "erste" Pakete durchzulassen, die auch korrekterweise das SYN-Flag gesetzt haben. Sonst lässt man im Zweifel Pakete bis zum Host durch, von denen wir schon wissen, dass sie nicht koscher sind, und dass der Host sie eh nur verwerfen wird.

Auf Unix-ähnlichen Systemen gibt es noch eine weitere Unterscheidung: Die Ports 1-1023 bleiben dem Benutzer root vorbehalten; nur Prozesse, die als root laufen, dürfen diese Ports des lokalen Systems verwenden. Man sieht deswegen in Firewallregeln wie den oberen oft die Begrenzung auf die "hohen" Ports ab 1024. Eine solche Begrenzung bringt aber keine zusätzliche Sicherheit, denn ein Prozess, der einen der "niedrigen" Ports benutzen darf, könnte genauso gut einen "hohen" Port verwenden. Ich empfehle deswegen das KISS-Prinzip und den allgemeinen Verzicht auf Beschränkungen des Source-Ports bei so einfachen Regeln.

Aus diesen Informationen dürfte klar sein, dass an Herstellerdokumentationen "erlauben Sie Port 80 TCP/UDP" oder "Wir benutzen die Ports 514 und 443 incoming und outgoing" oder "benötigt: Port 1024-65535" wenig Sachkenntnis beteiligt war. Wer stur nach solchen Regeln arbeitet, reißt sich große Sicherheitslöcher in seine Infrastruktur und ist nur noch durch das vielleicht vorhandene NAT vor den fatalen Folgen solcher Konfigurationsfehlern geschützt - oder eben nicht.

Je länger die Portliste, desto höher ist die Wahrscheinlichkeit, dass manche dieser Ports nur noch aus historischen Gründen in der Liste stehen und von der Applikation seit etwa 1948 nicht mehr genutzt werden. Gerne sieht man das bei Applikationen, die unter Windows entweder Laufwerke mappen wollen oder in irgend einer Art mit dem Active Directory sprechen: Microsoft hat diese beiden Zugriffsmethoden in den letzten zehn Jahren mehrfach umspezifiziert und jedes Mal neue Ports verwendet, und die älteren Portnummern braucht man nur, wenn auch noch ältere Versionen im Einsatz sind. In aktuellen Netzen reißt man sich damit potenzielle Sicherheitslöcher, denn auch die aktuellen Server lauschen natürlich im Interesse der Rückwärtskompatibilität auch auf den "älteren" Ports.

Viele andere Ports aus solchen ellenlangen Listen werden nur dann benötigt, wenn man ein bestimmtes obskures Feature der Software verwendet. Oder ein Eintrag in einer Portliste ist schlicht und einfach inkorrekt. Auch schon passiert: Ein essentiell wichtiger Port steht aus irgend einem Grund nicht in der Liste und lässt die Applikation auch dann subtil versagen, wenn man die Portdokumentation sklavisch in Firewallregeln konvertiert hat.

Deswegen lautet meine Empfehlung ganz klar, vom Hersteller einer Software gelieferte Portlisten komplett zu ignorieren und aus tcpdump und Firewall-Log herauszudestillieren, welche Kommunikationsbeziehungen die Applikation im gegebenen Anwendungsszenario wirklich zu benutzen gedenkt. Das funktioniert allerdings selten auf Anhieb, weil oftmals der nächste Port erst benutzt wird, wenn der Zugriff auf den erstfreigegebenen Port erfolgreich war. Man ist also gut beraten, wenn man die Applikation entweder selbst bedient oder den Anwender vorher darauf vorbereitet, dass man mehrere Iterationen von "probier's nochmal, ah ja, moment" benötigen wird bis die Applikation benutzbar sein wird - denn sonst wird einem diese Trial-and-Error-Methode gerne als unstrukturiertes oder unfähiges Vorgehen missinterpretiert. Außerdem muss man darauf vorbereitet sein, im Rahmen dieser Vorgehensweise auch die obskureren Funktionen der Software bis hin zum "Agent-Update auf dem Client" auszuprobieren, denn sonst fällt einem die Sicherheitspolicy vielleicht irgendwann im laufenden Betrieb schmerzhaft auf den Fuß.

Wenn man die aufwändige Phase einmal abgeschlossen hat, wird man nicht selten mit einem schlanken, gut dokumentierten Regelwerk belohnt, von dem man weiß, dass es keine unnötigen Risiken enthält. Außerdem bekommt man durch die Arbeit mit dem Firewall-Log und tcpdump ein Gefühl für die Kommunikation und genug Erfahrung mit den Tools, um später im Fehlerfall souverän mit den Tools umgehen zu können und deren Ausgabe sinnvoll interpretieren zu können. Und es erspart einem unnötige Aktionen mit der Glaskugel um zu raten, was der Hersteller mit seiner unvollständigen Dokumentation, die nicht selten stur aus einer Portliste ohne Protokoll- und Richtungsangabe besteht, wohl gemeint haben könnte.

Abschließend noch eine Wunschliste: Wenn Ihr den Firewallbetreuern Eurer Anwender einen großen Gefallen tut, dann beschreibt die Kommunikationsbeziehungen Eurer Software vollständig. Das bedeutet also im Zweifel eine Liste wie hier:

name=DNS proto=(UDP/TCP) srcip=(1) dstip=(2) dstport=53
name=http proto=TCP srcip=(1) dstip=ivanova.notwork.de,*.zugschlus.de dstport=80
name=amanda-control proto=UDP srcip=client dstip=server dstport=10080
name=amanda-data proto=TCP srcip=client srcport=50000 dstip=server dstport=50000-50100

(1)=IP-Adresse des lokalen Systems
(2)=Full Service Resolver für das lokale System

Dokumentation gehört zum Regelwerk dazu, denn man möchte auch in zwei Jahren noch verstehen, warum man das, was da drin steht, auch reingeschrieben hat. Deswegen liefert Eurem Firewaller bitte auch, wie das System heißt, für das da die Regeln eingetragen werden sollen, und was es tut. Er wird dann noch das aktuelle Datum und Euren Namen dazuschreiben, und dann ist die Dokumentation brauchbar.

Wenn es sich um ein Testsystem handelt, ist es sinnvoll, die damit verbundenen Regeln zeitlich zu beschränken. Dazu muss der Firewaller aber wissen, dass es ein Test ist, und wie lange er voraussichtlich dauern wird. Manche Firewallsysteme können bei jeder Regel sofort ein Verfallsdatum dazuschreiben. ab der die Regel automatisch nicht mehr angewendet wird. Sonst muss man das halt manuell mit Kommentaren im Regelwerk machen. Geht auch.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

Christian on :

Sehr guter Artikel - Danke schön! thumb up

Hans Bonfigt on :

Wie immer: Systematisch aufbereitet, Grundlagen erläutert, sauber formuliert - unbedingt lesenswert und dafür

DANKE!

Herr B. on :

Die firewallfeindliche Protokolle kann man in gewissen Grenzen durch Koniguration zähmen, zumindest bei NFS und SIP klappte das ganz gut. FTP möchte allerdings einen schmerzhaften Tod sterben.

Nur in ganz wenigen Sonderfällen

syslog über udp (entsprechend höllisch unzuverlässig)

Add Comment

Markdown format allowed
Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.
Form options

Submitted comments will be subject to moderation before being displayed.