# Stateful Packet Inspection

Stateful Packet Inspection (SPI; deutsch Zustandsorientierte Paketüberprüfung) ist bei Firewalls eine Paketfiltertechnik, bei der jedes Datenpaket dynamisch einer Sitzung zugeordnet wird. Der Sitzungszustand wird in die Filterentscheidung mit einbezogen, wodurch ein größeres Schutzniveau erreicht wird als es mit einer zustandslosen Paketfilterung möglich ist.
Bei dieser Technik werden die ein- und ausgehenden Datenpakete auf Internet- und Transportschicht analysiert und deren zugehöriger Sitzungszustand in einer dynamischen Zustandstabelle gespeichert. Für die Entscheidung über die Weiterleitung eines Datenpakets wird neben statischen Paketfilterregeln auch der aktuelle Sitzungszustand herangezogen. So kann beispielsweise bei einem aus dem Internet erhaltenen Datenpaket berücksichtigt werden, ob bereits eine aufgebaute Verbindung zu dieser Netzwerkadresse existiert. Stateful Packet Inspection ist bei verbindungsorientierten Netzwerkprotokollen wie dem Transmission Control Protocol (TCP) am wirkungsvollsten, kann mit Einschränkungen aber auch bei verbindungslosen Protokollen wie dem User Datagram Protocol (UDP) eingesetzt werden. In Verbindung mit Deep Packet Inspection kann Stateful Packet Inspection auch auf der Anwendungsschicht angewandt werden.
Der Firewall-Hersteller Check Point nimmt für sich in Anspruch, diese Technik im Jahr 1993 erfunden zu haben.

## Funktionsweise

Kommuniziert beispielsweise ein Client A mit einem Webserver B über einen zustandslosen Paketfilter (also ohne Stateful Packet Inspection), so muss dieser in seinem Regelwerk zwei Verkehrsströme erlauben:
* Quelle A nach Ziel B mit Zielport 443 für den Dienst HTTPS, um die Anfrage an den Server zu senden.
* Quelle B nach Ziel A mit Quellport 443, um die HTTPS-Antwort vom Server zu empfangen.
Ein statisches Regelwerk erlaubt mehr als eigentlich nötig, da B jederzeit an A senden darf, auch wenn A gar keine Anfrage gestellt hat. Wenn A zudem mit beliebigen Webservern im Internet kommunizieren möchte, deren einzelne Adressen vorab nicht bekannt sind, müssten sämtliche Quelladressen für eingehende Pakete erlaubt werden, was den Sicherheitsgewinn des Paketfilters reduziert.
Bei der zustandsgesteuerten Filterung (also mit Stateful Packet Inspection) kann der Zustand der Verbindung in das Regelwerk mit einbezogen werden:
* Quelle A darf Pakete an Ziel B mit Zielport 443 senden, wenn sie zu einer neuen oder zu einer bestehenden Verbindung gehören.
* Quelle B darf nur Pakete an Ziel A senden, wenn sie zu einer bestehenden Verbindung gehören.
Der Paketfilter merkt sich, welche Verbindungen der Client A aufgebaut hat und erlaubt nur die passenden Antwortpakete von Quelle B. Dadurch kann B nicht von sich aus neue Verbindungen zu A initiieren. Neben den IP-Adressen und Ports kann der Paketfilter auch weitere Parameter prüfen, beispielsweise ob die Sequenznummer und die weiteren Header-Informationen des Transmission Control Protocols zum erwarteten Verbindungszustand passen. Dadurch erschwert der Paketfilter das IP-Spoofing.
Neben dem Sicherheitsgewinn kann durch die zustandsbasierte Paketfilterung auch der Regelsatz wesentlich übersichtlicher gestaltet werden. Anstatt für Hin- und Rückweg separate Regeln zu konfigurieren, genügt eine Regel für den Hinweg, die eine neue Verbindung zulässt. Für den Rückweg genügt eine allgemeine Regel, die Antwortpakete zu bereits bestehenden Verbindungen zulässt (im Linux Netfilter als „ESTABLISHED“ und „RELATED“ bezeichnet).
Zustandsbasierte Paketfilterung ist aufwendiger und erzeugt daher mehr CPU-Last als statische Paketfilterung. Der Verbindungszustand wird in einer Zustandstabelle im RAM gespeichert, was die maximale Anzahl gleichzeitiger Verbindungen limitiert. Die Löschung eines Eintrags in der Zustandstabelle erfolgt entweder, sobald die Verbindung von den Kommunikationspartnern abgebaut wurde, oder automatisch nach einem Timeout infolge von Inaktivität.

## Stateful Inspection bei UDP-Paketen

Auf den ersten Blick sieht eine Stateful Packet Inspection bei UDP-Paketen wie ein Widerspruch aus, da UDP im Gegensatz zu TCP zustandslos arbeitet. Die meisten Implementierungen (z. B. Linux-Netfilter) behandeln UDP trotzdem als stateful, in dem Sinne, dass beim Versenden einer Anforderung per UDP für kurze Zeit eine dynamische Firewall-Regel für die Antwortpakete erzeugt wird. Im Beispiel DNS-Anfragen werden dadurch nur Antwortpakete von den Nameservern erlaubt, die man selbst gefragt hat.
Manche Programme – z. B. Skype – benutzen dies in einem als Hole Punching bezeichneten Verfahren, um durch Firewalls Punkt-zu-Punkt-Verbindungen aufzubauen. Beide Teilnehmer erfahren vom Skype-Server, auf welcher IP-Adresse und welchem Port Skype bei der Gegenseite arbeitet. Dann schicken beide ein UDP-Paket an die Gegenseite. Dort werden diese Pakete beim Eintreffen zwar verworfen, weil keine Input-Regel existiert, erzeugen aber auf der Firewall des ausgehenden Rechners eine Regel, die ab dann 'Antworten' erlaubt. Danach können beide Seiten miteinander kommunizieren. Mit TCP würde das (trivial) nicht funktionieren, da die Firewall aufgrund von Sequenznummern echte Antwortpakete erkennen kann.

## Stateful Inspection bei ICMP

Wer Ping-Anfragen senden will, aber nicht auf Ping-Anfragen antworten möchte, definiert zuerst eine ausgehende Regel für ICMP, und danach eine eingehende Regel, die generell alle eingehenden Pakete zulässt, für die es bereits eine bestehende Sitzung gibt (RELATED). Die Ping-Antwort wird durchgelassen, wenn die Firewall anhand der Parameter aus dem Antwortpaket einen Zusammenhang zu der Ping-Anfrage erkennt. Dies funktioniert, obwohl es sich bei ICMP um ein verbindungsloses Protokoll handelt.

## Stateful Inspection bei FTP

FTP ist problematisch. Es werden zwei Ports, 'ftp' und 'ftp-data' (21 und 20), verwendet. 'ftp' wird für die Übertragung von Kommandos verwendet, während ftp-data für Datenübertragung (Dateiinhalte oder Verzeichnisinhalte) verwendet wird. Hierbei gibt es zwei verschiedene Arten (active mode und passive mode), in welcher Richtung die Datenverbindung (ftp-data) aufgebaut wird. Im Linux-Kernel gibt es ein Kernelmodul, welches das Zusammenspiel beider Ports beherrscht.

## Timeout

Sowohl TCP- als auch UDP-Verbindungen haben bei Stateful Packet Inspection immer einen zugewiesenen Timeout. Bei UDP, weil nicht erkennbar ist, wenn eine Verbindung beendet worden ist; bei TCP, weil es passieren kann, dass Verbindungen nicht ordnungsgemäß abgebaut werden. Der UDP-Timeout liegt üblicherweise im Bereich 20–40 Sekunden, bei TCP 15–60 Minuten.
Ist der Timeout nicht lang genug und werden legitime Verbindungen dadurch von der Firewall beendet, gibt es zwei Lösungsmöglichkeiten. Eine Verlängerung des Timeouts hilft zwar, erhöht aber auch den Speicherbedarf des Systems und reduziert die Sicherheit. Die bevorzugte Methode sollte daher der Einsatz von Keep-Alive-Paketen sein. Diese lassen sich in manchen Applikationen wie SSH-Clients oder auch im Betriebssystem konfigurieren.
Setzen des TCP-Keep-Alives unter Linux auf alle 120 Sekunden:

## Beispiele für die Implementierung von Stateful Firewalls

* Check Point Firewall-1 (Solaris, Windows, IPSO, RHEL, SPLAT)
* Pf (Paketfilter) (OpenBSD)
* Ipfw (FreeBSD)
* Iptables (Linux ab 2.4)
* Fritzbox
* OPNsense (basierend auf FreeBSD und ASLR von HardenedBSD)