In FreeBSD 5.3 wurde PF von OpenBSD in das Basissystem integriert. Bei PF handelt es sich um eine komplette, voll ausgestattete Firewall, die optional auch ALTQ (Alternatives Queuing) unterstützt. ALTQ stellt Quality of Service (QoS) zur Verfügung.
Das OpenBSD-Projekt pflegt die maßgebliche Referenz von PF in der PF FAQ. Peter Hansteen betreut ein sehr ausführliches PF-Tutorial unter http://home.nuug.no/~peter/pf/.
Bedenken Sie beim Studium der PF FAQ, dass die PF-Version von FreeBSD im Laufe der Jahre erheblich von der Version in OpenBSD abgewichen ist. Nicht alle Eigenschaften funktionieren unter FreeBSD genauso wie unter OpenBSD und umgekehrt.
Die FreeBSD packet filter mailing list ist ein guter Anlaufpunkt für Fragen zur Konfiguration und dem Einsatz der PF-Firewall. Überprüfen Sie aber zunächst die Archive der Mailingliste, bevor Sie eine Frage stellen. Vielleicht wurde die Frage dort schon beantwortet.
Dieser Abschnitt konzentriert sich auf PF in FreeBSD. Es wird beschrieben, wie PF und ALTQ aktiviert werden. Zusätzlich wird demonstriert, wie Regelsätze auf einem FreeBSD-System erstellt werden.
Um PF zu benutzen,
muss zunächst das Kernelmodul geladen werden. Dieser
Abschnitt beschreibt die Einträge für
/etc/rc.conf
, die verwendet werden können
um PF zu aktivieren.
Beginnen Sie damit pf_enable=yes
in
/etc/rc.conf
hinzuzufügen:
#
sysrc pf_enable=yes
pfctl(8) beschreibt zusätzliche Optionen, die beim
Start an PF übergeben werden
können. Fügen Sie diesen Eintrag in
/etc/rc.conf
hinzu und schreiben Sie die
benötigten Optionen zwischen die Anführungszeichen:
pf_flags="" # additional flags for pfctl startup
PF kann nicht gestartet werden,
wenn es seine Konfigurationsdatei nicht findet. In der
Voreinstellung existiert unter FreeBSD kein Regelsatz namens
/etc/pf.conf
. Beispiel-Regelsätze finden
Sie in /usr/share/examples/pf/
. Wenn bereits ein Regelsatz
an anderer Stelle gespeichert wurde, fügen Sie in
/etc/rc.conf
einen Eintrag mit dem
vollständigen Pfad zur Datei ein:
pf_rules="/path/to/pf.conf
"
Protokollierungsfunktionen für
PF werden von pflog(4) zur
Verfügung gestellt. Fügen Sie
pflog_enable=yes
in
/etc/rc.conf
ein, um diese Funktion zu
aktivieren:
#
sysrc pflog_enable=yes
Die folgenden Zeilen können zusätzlich hinzugefügt werden, um den Speicherort der Protokolldatei zu bestimmen und weitere Optionen beim Start an pflog(4) zu übergeben:
pflog_logfile="/var/log/pflog" # where pflogd should store the logfile pflog_flags="" # additional flags for pflogd startup
Falls ein LAN hinter der Firewall existiert und die Pakete an die Rechner im LAN weitergeleitet werden müssen, oder wenn NAT benötigt wird, aktivieren Sie die folgende Option:
gateway_enable="YES" # Enable as LAN gateway
Nachdem die Änderungen gespeichert wurden, kann PF mit Unterstützung für Protokollierung gestartet werden:
#
service pf start
#
service pflog start
In der Voreinstellung liest PF
seine Konfiguration aus /etc/pf.conf
und
modifiziert, verwirft oder akzeptiert Pakete anhand der
Definitionen in dieser Datei. FreeBSD enthält mehrere
Beispieldateien unter
/usr/share/examples/pf/
. Auch die
PF
FAQ enthält sehr ausführliche Beispiele für
PF-Regeln.
Zur Steuerung von PF wird
pfctl
verwendet. Tabelle 30.1, „Nützliche pfctl
Optionen“
fasst einige nützliche Optionen für diesen Befehl zusammen.
Eine Beschreibung aller verfügbaren Optionen finden Sie in
pfctl(8).
pfctl
OptionenKommando | Aufgabe |
---|---|
pfctl -e | PF aktivieren |
pfctl -d | PF deaktivieren |
pfctl -F all -f
/etc/pf.conf | Alle Filterregeln zurücksetzen
(NAT, Filter, Zustandstabelle) und
/etc/pf.conf erneut
einlesen. |
pfctl -s [ rules | nat |
states ] | Zusammenfassung der Filterregeln, NAT-Regeln, oder der Zustandstabelle. |
pfctl -vnf
/etc/pf.conf | Überprüft /etc/pf.conf auf
Fehler, lädt aber die Filterregeln nicht neu. |
security/sudo ist nützlich um
Kommandos mit erhöhten Berechtigungen auszuführen, wie
beispielsweise pfctl
. Das Programm kann
aus der Ports-Sammlung installiert werden.
Um den ein- und ausgehenden Verkehr im Auge zu behalten, können Sie ein Werkzeug wie sysutils/pftop benutzen. Sobald das Programm installiert ist, können Sie pftop ausführen, um einen Snapshot des Datenverkehrs zu sehen. Das Format der Ausgabe ist der von top(1) sehr ähnlich.
Dieser Abschnitt beschreibt die Erstellung von angepassten Regelsätzen. Es wird mit dem einfachsten Regelsatz begonnen auf dem dann weitere aufgebaut werden, um die Konzepte und Funktionen von PF an einigen konkreten Beispielen zu verdeutlichen.
Der einfachste Regelsatz gilt für einen Rechner, der
keine Dienste anbietet und Zugriff auf das Internet haben
soll. Für diesen minimalen Regelsatz wird
/etc/pf.conf
wie folgt
konfiguriert:
block in all pass out all keep state
Die erste Regel blockiert jeglichen eingehenden Datenverkehr. Die zweite Regel erlaubt ausgehende Verbindungen von diesem Rechner, während die Zustandsinformationen dieser Verbindungen gespeichert werden. Diese Zustandsinformationen machen es möglich, den Antwortverkehr für diese Verbindungen zu erlauben. Der Regelsatz wird mit dem folgenden Befehl geladen:
#
pfctl -e ; pfctl -f /etc/pf.conf
Neben den Zustandsinformationen verfügt PF über Listen und Makros. Diese können bei der Erstellung der Regeln definiert werden. Makros können Listen enthalten und sie müssen vor ihrer ersten Benutzung definiert sein. Fügen Sie beispielsweise folgende Zeilen an den Anfang des Regelsatzes:
tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }" udp_services = "{ domain }"
PF versteht sowohl Portnamen
als auch Portnummern, solange die Namen in
/etc/services
aufgeführt sind. Dieses
Beispiel erstellt zwei Makros. Das erste ist eine Liste mit
sieben TCP-Portnamen, die zweite Liste
enthält einen UDP-Portnamen. Sobald ein
Makro definiert ist, kann es in den Regeln verwendet werden.
In diesem Beispiel wird der gesamte Datenverkehr geblockt, mit
Ausnahme der Verbindungen die von diesem Rechner initiiert
wurden und sich auf einen der angegebenen
TCP-Dienste oder den
UDP-Dienst beziehen:
tcp_services = "{ ssh, smtp, domain, www, pop3, auth, pop3s }" udp_services = "{ domain }" block all pass out proto tcp to any port $tcp_services keep state pass proto udp to any port $udp_services keep state
Obwohl UDP als zustandsloses Protokoll betrachtet wird, ist PF in der Lage einige Zustandsinformationen zu verfolgen. Wenn beispielsweise eine UDP-Abfrage für einen Nameserver das System verlässt, wird PF nach der Antwort Ausschau halten und das Antwortpaket durch lassen.
Nachdem der Regelsatz verändert wurde, muss er neu geladen werden:
#
pfctl -f /etc/pf.conf
Wenn keine Syntaxfehler festgestellt werden, wird
pfctl
keine Ausgabe erzeugen. Die Syntax
kann auch getestet werden, bevor der Regelsatz geladen
wird:
#
pfctl -nf /etc/pf.conf
Die Option -n
bewirkt, dass die Regeln
nur interpretiert, jedoch nicht geladen werden. Dies bietet
die Möglichkeit, alle Fehler zu korrigieren. Es wird immer
der letzte gültige Regelsatz geladen, bis
PF entweder deaktiviert, oder ein
neuer Regelsatz geladen wird.
Wenn Sie beim Laden oder Prüfen des Regelsatzes noch die
Option -v
hinzufügen, wird
pfctl
den komplett interpretierten
Regelsatz anzeigen. Dies ist äußerst nützlich, wenn Sie
versuchen Fehler im Regelsatz zu finden.
Dieser Abschnitt zeigt wie ein FreeBSD-System mit
PF als Gateway konfiguriert wird.
Das Gateway muss über mindestens zwei Netzwerkkarten
verfügen, die jeweils mit einem separaten Netzwerk verbunden
sind. In diesem Beispiel ist xl1
mit
dem Internet verbunden und xl0
ist mit
dem internen Netzwerk verbunden.
Aktivieren Sie zunächst das Gateway, damit der Rechner den Netzwerkverkehr von einer Schnittstelle zur nächsten weiterleiten kann. Diese sysctl-Einstellung sorgt dafür, dass IPv4-Pakete weitergeleitet werden:
#
sysctl net.inet.ip.forwarding=1
So leiten Sie IPv6-Datenverkehr weiter:
#
sysctl net.inet6.ip6.forwarding=1
Um diese Einstellungen beim Systemstart zu aktivieren,
fügen Sie sie mit Hilfe von sysrc(8) in
/etc/rc.conf
ein:
#
sysrc gateway_enable=yes
#
sysrc ipv6_gateway_enable=yes
Prüfen Sie mit ifconfig
, dass beide
Schnittstellen vorhanden und aktiv sind.
Als nächstes erstellen Sie die nötigen PF-Regeln, damit das Gateway den Datenverkehr weiterleiten kann. Die folgende Regel erlaubt den zustandsorientierten Verkehr aus dem Internet zu den Rechnern im Netzwerk:
pass in on xl1 from xl1:network to xl0:network port $ports keep state
Diese Regel erlaubt lediglich den Datenverkehr über das Gateway auf der internen Schnittstelle. Damit die Pakete noch weiter gehen, wird eine passende Regel benötigt:
pass out on xl0 from xl1:network to xl0:network port $ports keep state
Obwohl diese beiden Regeln funktionieren, werden sie in der Praxis so spezifisch selten benötigt. Ein lesbarer Regelsatz ist oft ein sicherer Regelsatz. Der Rest dieses Abschnitts zeigt, wie Sie die Regeln so einfach und lesbar wie möglich halten. Zum Beispiel könnten die beiden Regeln zu einer Regel zusammengefasst werden:
pass from xl1:network to any port $ports keep state
Die Notation interface:network
kann
durch ein Makro ersetzt werden, um den Regelsatz besser
lesbar zu machen. Zum Beispiel könnte für das Netzwerk an
der internen Schnittstelle (xl0:network
)
ein Makro namens $localnet
definiert
werden. Alternativ könnte für die Definition von
$localnet
auch eine
IP-Adresse/Netzmaske Notation verwendet
werden, um ein Netzwerk zu bezeichnen, beispielsweise
192.168.100.1/24
für ein privates
Subnetz.
Bei Bedarf kann für $localnet
auch
eine Liste von Netzwerken definiert werden. Abhängig von
den Bedürfnissen kann $localnet
auch für
eine typische Regel wie folgt verwendet werden:
pass from $localnet to any port $ports keep state
Der folgende Regelsatz erlaubt sämtlichen Verkehr, der von den Rechnern im internen Netzwerk initiiert wird. Zunächst werden zwei Makros definiert, die die externen und internen 3COM-Schnittstellen repräsentieren.
Bei Einwählverbindungen wird tun0
für die externe Schnittstelle verwendet. Bei
ADSL-Verbindungen, insbesondere denen
die PPP over Ethernet
(PPPoE) verwenden, ist die richtige
externe Schnittstelle tun0
und nicht
die physische Ethernet-Schnittstelle.
ext_if = "xl0" # macro for external interface - use tun0 for PPPoE int_if = "xl1" # macro for internal interface localnet = $int_if:network # ext_if IP address could be dynamic, hence ($ext_if) nat on $ext_if from $localnet to any -> ($ext_if) block all pass from { lo0, $localnet } to any keep state
Dieser Regelsatz führt die NAT-Regel
ein, die verwendet wird, um die Übersetzung der
Netzwerkadressen von den nicht-routebaren Adressen im
internen Netzwerk auf die IP-Adresse der
externen Schnittstelle zu handhaben. Die Klammern im
letzten Teil der NAT-Regel
($ext_if)
werden angegeben, wenn die
IP-Adresse der externen Schnittstelle
dynamisch zugewiesen wird. Damit wird sichergestellt, dass
der Netzwerkverkehr ohne schwerwiegende Unterbrechungen
weiterläuft, auch wenn sich die externe
IP-Adresse ändert.
Beachten Sie, dass dieser Regelsatz wahrscheinlich mehr Verkehr aus dem Netzwerk zulässt, als eigentlich nötig ist. Bei einem angemessenen Aufbau könnte folgendes Makro erstellt werden:
client_out = "{ ftp-data, ftp, ssh, domain, pop3, auth, nntp, http, \ https, cvspserver, 2628, 5999, 8000, 8080 }"
Dieses Makro wird dann in der Filterregel benutzt:
pass inet proto tcp from $localnet to any port $client_out \ flags S/SA keep state
Weitere pass
Regeln werden
vielleicht noch benötigt. Diese Regel aktiviert
SSH auf der externen
Schnittstelle:
pass in inet proto tcp to $ext_if port ssh
Dieses Makrodefinition und Regel erlaubt DNS und NTP für interne Clients:
udp_services = "{ domain, ntp }" pass quick inet proto { tcp, udp } to any port $udp_services keep state
Beachten Sie das Schlüsselwort quick
in dieser Regel. Da der Regelsatz aus mehreren Regeln
besteht, ist es wichtig, die Beziehungen zwischen den
einzelnen Regeln zu verstehen. Die Regeln werden von oben
nach unten ausgewertet, in der Reihenfolge wie sie
geschrieben sind. Für jedes Paket oder jede Verbindung, das
PF ausgewertet, wird die letzte
übereinstimmende Regel im Regelsatz angewendet. Wenn jedoch
ein Paket auf eine Regel passt, welche das Schlüsselwort
quick
enthält, wird das Paket
entsprechend dieser Regel behandelt und die
Regelverarbeitung wird gestoppt. Diese Vorgehensweise ist
sehr nützlich, wenn eine Ausnahme von den allgemeinen Regeln
erforderlich ist.
Die Konfiguration einer funktionierenden Regel für FTP kann aufgrund der Beschaffenheit des FTP-Protokolls problematisch sein. FTP ist sehr viel älter als Firewalls und schon vom Design her unsicher. Die häufigsten Argumente gegen eine Verwendung von FTP sind:
Passwörter werden im Klartext übertragen.
Das Protokoll erfordert die Verwendung von mindestens zwei TCP-Verbindungen (Steuerung und Daten) auf separaten Ports.
Wenn eine Sitzung aufgebaut wird, werden die Daten auf zufällig ausgewählten Ports übermittelt.
All diese Punkte stellen Herausforderungen dar, noch bevor die Client- oder Server-Software auf potenzielle Sicherheitslücken überprüft wurde. Es existieren aber auch sichere Alternativen für die Dateiübertragung, wie sftp(1) oder scp(1), wo die Authentifizierung und die Datenübertragung über eine verschlüsselte Verbindung erfolgt.
Für Situationen, in denen FTP erforderlich ist, kann PF den FTP-Datenverkehr an ein kleines Proxy-Programm namens ftp-proxy(8) weiterleiten. Dieses Programm ist im Basissystem von FreeBSD enthalten. Die Aufgabe des Proxies ist das dynamische Einfügen und Entfernen von Regeln im Regelsatz. Dies wird durch den Einsatz von Ankern erreicht, damit der FTP-Verkehr korrekt verarbeitet werden kann.
Fügen Sie folgende Zeilen in
/etc/rc.conf
ein, um den Proxy zu
aktivieren:
ftpproxy_enable="YES"
Danach kann der Proxy mit service ftp-proxy
start
gestartet werden.
Für die Grundkonfiguration müssen drei weitere Einträge
in /etc/pf.conf
hinzugefügt werden.
Zunächst werden die Anker hinzugefügt, die der Proxy für die
FTP-Sitzungen verwendet:
nat-anchor "ftp-proxy/*" rdr-anchor "ftp-proxy/*"
Dann wird eine pass
-Regel benötigt,
damit der FTP-Datenverkehr durch den
Proxy geleitet werden kann.
Die Regeln für Umleitung und NAT
müssen vor den eigentlichen Filterregeln definiert werden.
Fügen Sie diese rdr
-Regel unmittelbar
nach der NAT-Regel ein:
rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021
Zum Schluss muss der umgeleitete Verkehr die Firewall passieren dürfen:
pass out proto tcp from $proxy to any port ftp
$poxy
enthält die Adresse, an dem der
Proxy-Daemon gebunden ist.
Speichern Sie /etc/pf.conf
und
laden Sie die Regeln neu. Prüfen Sie von einem Client, ob
die FTP-Verbindungen
funktionieren:
#
pfctl -f /etc/pf.conf
Dieses Beispiel umfasst eine Grundkonfiguration, in der
die Rechner im lokalen Netzwerk Zugriff auf entfernte
FTP-Server benötigen. Diese
Konfiguration sollte mit den meisten
FTP-Clients und -Servern gut
funktionieren. Das Verhalten von ftp-proxy(8) kann
durch diverse Optionen in ftpproxy_flags
beeinflusst werden. Einige Clients und Server haben
bestimmte Marotten, die bei der Konfiguration berücksichtigt
werden müssen. Es kann zum Beispiel notwendig sein, den
FTP-Datenverkehr für den Proxy einer
bestimmten Warteschlange zuzuweisen.
Es besteht auch die Möglichkeit einen
FTP-Server mit
PF und ftp-proxy(8) zu
schützen. Konfigurieren Sie einen separaten
ftp-proxy
mit -R
für den
Reverse-Modus auf einem separaten Port und einer eigenen
Umleitungsregel.
Viele Werkzeuge zur Fehlerbehebung in TCP/IP-Netzwerken verlassen sich auf das Internet Control Message Protocol (ICMP), das speziell für diese Zwecke entwickelt wurde.
Das ICMP-Protokoll sendet und empfängt Kontrollnachrichten zwischen Rechnern und Gateways, hauptsächlich um ungewöhnliche Bedingungen auf dem Weg zum Zielrechner zu berichten. Router verwenden ICMP um Paketgrößen und andere Übertragungsparameter zu ermitteln. Dieser Prozess ist auch als Path MTU Discovery bekannt.
Aus der Sicht einer Firewall sind einige ICMP-Kontrollnachrichten anfällig für bekannte Angriffsmethoden. Zwar ist die Fehlerbehebung einfacher, wenn alle ICMP-Pakete bedingungslos durch gelassen werden, aber dass macht es auch für Angreifer leichter, Informationen über das Netzwerk zu extrahieren. Aus diesen Gründen ist die folgende Regel nicht optimal:
pass inet proto icmp from any to any
Eine Lösung besteht darin, nur den ICMP-Verkehr aus dem lokalen Netz zu akzeptieren, während ICMP-Pakete von außerhalb des Netzwerks verworfen werden:
pass inet proto icmp from $localnet to any keep state pass inet proto icmp from any to $ext_if keep state
Es stehen noch weitere Optionen zur Verfügung, die die Flexibilität von PF demonstrieren. Anstatt beispielsweise alle ICMP-Nachrichten zu erlauben, kann man die Nachrichten angeben, die von ping(8) und traceroute(8) verwendet werden. Beginnen Sie damit, ein Makro für diese Art von Nachrichten zu definieren:
icmp_types = "echoreq"
Erstellen Sie dann eine Regel, die das eben erstellte Makro benutzt:
pass inet proto icmp all icmp-type $icmp_types keep state
Wenn weitere Arten von
ICMP-Nachrichten benötigt werden, kann
die Liste icmp_types
einfach erweitert
werden. Geben Sie more
/usr/src/sbin/pfctl/pfctl_parser.c
ein, um
eine Liste der von PF
unterstützten ICMP-Nachrichten zu sehen.
Die Webseite
http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
enthält eine Erklärung für jeden Nachrichtentyp.
Da UNIX® traceroute
in der
Voreinstellung UDP verwendet, wird eine
weitere Regel benötigt:
# allow out the default range for traceroute(8): pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state
Da TRACERT.EXE
unter
Microsoft® Windows®-Systemen ICMP Echo
Request Meldungen verwendet, ist nur die erste Regel
notwendig um Traces für solche Systeme zu ermöglichen.
UNIX® traceroute
kann aber auch andere
Protokolle verwenden, zum Beispiel ICMP
Echo Request, wenn der Schalter -I
benutzt
wird. Details finden Sie in traceroute(8).
Internet-Protokolle sind so ausgelegt, dass sie
geräteunabhängig sind. Eine Folge davon ist, dass die
optimale Paketgröße nicht immer zuverlässig vorhergesagt
werden kann. Das größte Hindernis ist hier die
Maximum Transmission Unit
(MTU
), welche die Obergrenze für die
Paketgröße festlegt. Die MTU für die
Schnittstelle des Systems können Sie sich mit
ifconfig
anzeigen lassen.
TCP/IP benutzt ein Verfahren, das
als path MTU discovery
bekannt ist, um die korrekte Paketgröße für eine
Verbindung zu bestimmen. Dieses Verfahren sendet Pakete
unterschiedlicher Größe mit dem Flag „do not
fragment“ und erwartet ein
ICMP-Antwortpaket vom Typ
„type 3, code 4“, wenn die Obergrenze
erreicht worden ist. Typ 3 bedeutet „Ziel nicht
erreichbar“ und Code 4 ist die Abkürzung für
„Fragmentierung nötig, aber Do-not-Fragment Flag ist
gesetzt“. Um path MTU
discovery zu erlauben und damit
Verbindungen zu anderen MTUs zu
unterstützen, fügen Sie dem Makro
icmp_types
den Typ destination
unreachable
hinzu:
icmp_types = "{ echoreq, unreach }"
Da die pass
-Regel bereits das Makro
verwendet, braucht es nicht geändert werden um den neuen
ICMP-Typ zu unterstützen:
pass inet proto icmp all icmp-type $icmp_types keep state
PF kann alle Variationen von ICMP-Typen und Codes filtern. Eine Liste der verfügbaren Typen und Codes ist in icmp(4) und icmp6(4) dokumentiert.
Manchmal sind bestimmte Daten für die Filterung und
Weiterleitung interessant, jedoch wäre eine Definition einer
solchen Filterregel für einen Regelsatz viel zu lang.
PF unterstützt die Verwendung von
Tabellen. Dies sind definierte Listen, die verändert werden
können, ohne den gesamten Regelsatz neu laden zu müssen.
Zudem können diese Listen sehr schnell durchsucht werden.
Tabellennamen sind immer in < >
eingeschlossen und sehen wie folgt aus:
table <clients> { 192.168.2.0/24, !192.168.2.5 }
In diesem Beispiel ist das Netzwerk
192.168.2.0/24
Teil der Tabelle.
192.168.2.5
wurde im dem Operator
!
ausgeschlossen und ist somit nicht Teil
der Tabelle. Es ist auch möglich Tabellen aus Dateien zu
laden, wo jeder Eintrag in einer separaten Zeile steht.
Dieses Beispiel verwendet dazu die Datei
/etc/clients
:
192.168.2.0/24 !192.168.2.5
Um sich auf diese Datei zu beziehen, definieren Sie die Tabelle wie folgt:
table <clients> persist file "/etc/clients"
Sobald die Tabelle definiert ist, kann eine Filterregel Bezug darauf nehmen:
pass inet proto tcp from <clients> to any port $client_out flags S/SA keep state
Die Inhalte einer Tabelle können mit
pfctl
direkt verändert werden. Dieses
Beispiel fügt ein weiteres Netzwerk zur Tabelle
hinzu:
#
pfctl -t clients -T add 192.168.1.0/16
Beachten Sie, dass auf diese Weise vorgenommene
Änderungen direkt übernommen werden, jedoch bei einem
Neustart des Systems oder bei einem Stromausfall verloren
gehen. Um die Änderungen dauerhaft zu speichern, müssen sie
in der Definition der Tabelle oder in der Datei, auf die
sich die Tabelle bezieht, bearbeitet werden. Mit einem
cron(8) Job und einem Befehl wie
pfctl -t clients -T show >/etc/clients
können Sie auch eine Kopie der Tabelle auf Platte speichern
und dann in regelmäßigen Abständen aktualisieren.
Alternativ kann /etc/clients
auch mit
den Tabelleneinträgen, die sich aktuell im Speicher
befinden, aktualisiert werden.
#
pfctl -t clients -T replace -f /etc/clients
Benutzer, die SSH auf einer externen Schnittstelle ausführen, haben wahrscheinlich schon einmal ähnliche Meldungen in den Protokolldateien gesehen:
Sep 26 03:12:34 skapet sshd[25771]: Failed password for root from 200.72.41.31 port 40992 ssh2 Sep 26 03:12:34 skapet sshd[5279]: Failed password for root from 200.72.41.31 port 40992 ssh2 Sep 26 03:12:35 skapet sshd[5279]: Received disconnect from 200.72.41.31: 11: Bye Bye Sep 26 03:12:44 skapet sshd[29635]: Invalid user admin from 200.72.41.31 Sep 26 03:12:44 skapet sshd[24703]: input_userauth_request: invalid user admin Sep 26 03:12:44 skapet sshd[24703]: Failed password for invalid user admin from 200.72.41.31 port 41484 ssh2
Diese Meldungen deuten auf einen Brute-Force-Angriff hin, bei dem ein Angreifer oder ein Programm versucht, den Benutzernamen und das Passwort zu erraten, um Zugriff auf das System zu bekommen.
Wenn der Zugriff über SSH für
berechtigte Benutzer erforderlich ist, kann eine Änderung
des Standard-Ports für SSH einen gewissen
Schutz bieten. Allerdings bietet
PF eine elegantere Lösung für
dieses Problem. pass
-Regeln können
Einschränkungen für Dinge enthalten, die ein verbindender
Rechner tun kann. Bei einem Verstoß gegen diese
Einschränkungen kann dann dem betroffenen Rechner der
Zugriff teilweise oder ganz entzogen werden. Es ist sogar
möglich, alle bestehenden Verbindungen zu trennen, falls die
Grenze überschritten wird.
Um dies zu konfigurieren, erstellen Sie folgende Tabelle im Regelsatz:
table <bruteforce> persist
Fügen Sie dann ziemlich am Anfang der Filterregeln folgende Regeln hinzu, um die Brute-Force-Angriffe zu blocken und gleichzeitig berechtigte Verbindungen zu erlauben:
block quick from <bruteforce> pass inet proto tcp from any to $localnet port $tcp_services \ flags S/SA keep state \ (max-src-conn100
, max-src-conn-rate15/5
, \ overload <bruteforce> flush global)
Der Teil in Klammern definiert die Grenzwerte. Die Zahlen sollten an die lokalen Anforderungen angepasst werden. Die Zeilen können wie folgt interpretiert werden:
max-src-conn
definiert die maximal
erlaubte Anzahl gleichzeitiger Verbindungen von einem
Rechner.
max-src-conn-rate
definiert die
maximal erlaubte Anzahl neuer Verbindungen eines einzelnen
Rechners (15
) pro Anzahl von
Sekunden (5
).
overload <bruteforce>
bedeutet,
dass jeder Rechner, der diesen Grenzwert überschreitet, zur
Tabelle bruteforce
hinzugefügt wird.
Diese Filterregel blockiert jeglichen Datenverkehr von
Adressen aus der Tabelle
bruteforce
.
flush global
besagt, dass alle
(global
) Verbindungen dieses Rechners
getrennt (flush
) werden, wenn der
Grenzwert erreicht wird.
Diese Filterregeln helfen nicht bei langsamen Brute-Force-Angriffen, wie sie in http://home.nuug.no/~peter/hailmary2013/ beschrieben sind.
Dieser Beispielregelsatz dient lediglich als Illustration. Wenn Sie allgemein eine große Anzahl an Verbindungen erlauben wollen, aber gleichzeitig bei SSH etwas restriktiver vorgehen möchten, können Sie die obige Regel ergänzen:
pass quick proto { tcp, udp } from any to any port ssh \ flags S/SA keep state \ (max-src-conn 15, max-src-conn-rate 5/3, \ overload <bruteforce> flush global)
Es ist zu erwähnen, dass der
overlaod
-Mechanismus eine allgemeine
Technik darstellt, die nicht auf SSH
beschränkt ist. Außerdem ist es nicht immer optimal,
Datenverkehr von aggressiven Rechnern zu
blockieren.
Eine overload
-Regel kann
beispielsweise benutzt werden, um einen Mail- oder
Webserver zu schützen. Die
overload
-Tabelle könnte dann in einer
Regel verwendet werden, um aggressive Rechner einer
Warteschlange mit geringerer Bandbreite zuzuweisen, oder
den Rechner auf eine bestimtme Webseite umzuleiten.
Im Laufe der Zeit werden die Tabellen durch die
overload
-Regeln immer größer und belegen
immer mehr Speicher. Manchmal wird eine geblockte
IP-Adresse einem Rechner dynamisch
zugewiesen, der eigentlich berechtigt ist, mit den Rechnern
im lokalen Netzwerk zu kommunizieren.
Für solche Situationen bietet pfctl
die Möglichkeit, Tabelleneinträge auslaufen zu lassen.
Dieses Kommando würde beispielsweise Einträge aus der
Tabelle <bruteforce>
löschen,
die seit 86400
Sekunden nicht mehr
referenziert wurden:
#
pfctl -t bruteforce -T expire 86400
Eine ähnliche Funktionalität bietet security/expiretable, welches Einträge entfernt, die für einen bestimmten Zeitraum nicht referenziert wurden.
Nach der Installation kann
expiretable benutzt werden, um
Einträge aus der Tabelle
<bruteforce>
nach einer bestimmten
Zeit zu entfernen. Dieses Beispiel entfernt alle Einträge,
die älter sind als 24 Stunden:
/usr/local/sbin/expiretable -v -d -t 24h bruteforce
Im Gegensatz zum spamd-Daemon von spamassassin, kann mail/spamd zusammen mit PF den SPAM direkt an der Firewall abwehren. Dieser spamd wird in PF über einen Satz von Umleitungen konfiguriert.
Spammer neigen dazu, eine große Anzahl von Nachrichten zu versenden. Dabei nutzten Sie SPAM-freundliche Netzwerke und gekaperte Rechner, welche dann ziemlich schnell bei sogenannten Blacklists gemeldet werden.
Wenn eine SMTP-Verbindung von einer Adresse in der Blacklist empfangen wird, präsentiert spamd einen Banner und schaltet sofort in einen Modus, in dem die Antworten auf den SMTP-Verkehr jeweils ein Byte groß sind. Diese Technik, die möglichst viel Zeit des Spammers verschwenden soll, wird Tarpitting genannt. Die spezifische Implementierung, welche ein Byte SMTP-Antworten verwendet, wird als Stuttering bezeichnet.
Dieses Beispiel zeigt das grundlegende Verfahren zur Konfiguration von spamd mit automatisch aktualisierten Blacklists. Für weitere Informationen lesen die Manualpages, die zusammen mit mail/spamd installiert werden.
Installieren Sie das Paket oder den Port
mail/spamd. Um
spamd's Greylisting-Funktion
zu nutzen, muss fdescfs(5) in
/dev/fd
eingehängt werden. Fügen
Sie folgende Zeile in /etc/fstab
ein:
fdescfs /dev/fd fdescfs rw 0 0
Danach hängen Sie das Dateisystem ein:
#
mount fdescfs
Fügen Sie folgende Zeilen in den PF-Regelsatz ein:
table <spamd> persist table <spamd-white> persist rdr pass on $ext_if inet proto tcp from <spamd> to \ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025 rdr pass on $ext_if inet proto tcp from !<spamd-white> to \ { $ext_if, $localnet } port smtp -> 127.0.0.1 port 8025
Die beiden Tabellen <spamd>
und <spam-white>
sind von
großer Bedeutung. SMTP-Verkehr von
einer Adresse, die in <spamd>
aber nicht in <spamd-white>
ist, wird an den spamd-Daemon
auf Port 8025 umgeleitet.
Im nächsten Schritt wird
spamd in
/usr/local/etc/spamd.conf
konfiguriert und einige Parameter werden in
/etc/rc.conf
hinzugefügt.
Die Installation von mail/spamd
enthält eine Beispielkonfiguration
(/usr/local/etc/spamd.conf.sample
)
und eine Manualpage für spamd.conf
.
Beziehen Sie sich für zusätzliche Konfigurationsoptionen
auf diese Dokumentation.
Die Konfigurationsdatei enthält einen Block, in dem
die all
-Liste definiert ist, die
wiederum weitere Listen spezifiziert:
all:\ :traplist:whitelist:
Dieser Eintrag fügt die gewünschten Blacklists,
getrennt durch einen Doppelpunkt (:
),
hinzu. Um auch eine Whitelist zu verwenden, fügen Sie
den Namen unmittelbar hinter dem Namen der Blacklist
ein. Zum Beispiel:
:Blacklist:Whitelist:
.
Danach folgt die Definition der verwendeten Blacklist:
traplist:\ :black:\ :msg="SPAM. Your address %A has sent spam within the last 24 hours":\ :method=http:\ :file=www.openbsd.org/spamd/traplist.gz
In der ersten Zeile steht der Name der Blacklist und
die zweite Zeile gibt den Typ an. Das Feld
msg
enthält die Nachricht, die dem
Absender während des SMTP-Dialogs
angezeigt wird. Das Feld mehtod
legt
fest, wie spamd-setup die
Listen bezieht; unterstützte Methoden sind
http
, ftp
,
file
und ein externes Programm via
exec
. Im letzten Feld gibt
file
den Namen der Datei an, die
spamd erwartet.
Die Definition der Whitelist ist ähnlich. Das Feld
msg
wird jedoch nicht definiert, da
eine Meldung hier nicht erforderlich ist:
whitelist:\ :white:\ :method=file:\ :file=/var/mail/whitelist.txt
Bei der Verwendung von sämtlichen Blacklists aus
der Beispieldatei spamd.conf
würden große Teile des Internets geblockt. Der
Administrator muss diese Datei bearbeiten, um eine
optimale Konfiguration zu erzielen. Dazu gehört auch
die Auswahl von geeigneten Blacklists und, wenn nötig,
die Erstellung von benutzerdefinierten Listen.
Als nächstes fügen Sie folgenden Eintrag in
/etc/rc.conf
hinzu. Zusätzliche
Optionen sind in der Manualpage beschrieben:
spamd_flags="-v" # use "" and see spamd-setup(8) for flags
Wenn Sie fertig sind, starten Sie
spamd durch die Eingabe von
service obspamd start
. Führen Sie
die weitere Konfiguration mit
spamd-setup
durch. Erstellen Sie zum
Schluss einen cron(8)-Job, der
spamd-setup
in regelmäßigen Abständen
aufruft, um die Listen zu aktualisieren.
Auf einem typischen Gateway vor dem Mailserver, werden Rechner innerhalb von wenigen Minuten geblockt.
PF unterstützt auch
Greylisting, das Nachrichten von
unbekannten Rechnern vorübergehend mit
45n
-Codes ablehnt. Nachrichten
von diesen Rechnern werden bei einem erneuten Versuch nach
einer angemessenen Zeit durchgelassen. Nachrichten von
Rechnern, die nach RFC 1123 und RFC 2821 konfiguriert sind,
werden sofort durchgelassen.
Weitere Informationen über Greylisting finden Sie unter greylisting.org. Das Erstaunlichste an Greylisting ist, neben der einfachen Benutzung, dass es immer noch funktioniert. Spammer und Malware-Autoren gelingt es bislang nur schwer, diese Technik zu umgehen.
Die grundsätzliche Vorgehensweise zur Konfiguration von Greylisting ist wie folgt:
Stellen Sie sicher, dass fdescfs(5) eingehängt ist. Dies wird in Schritt 1 der vorherigen Prozedur beschrieben.
Um spamd im
Greylisting-Modus auszuführen, fügen Sie folgende Zeilen
in /etc/rc.conf
ein:
spamd_grey="YES" # use spamd greylisting if YES
Lesen Sie die Manualpage von spamd für Beschreibungen von zusätzlichen Parametern.
Starten Sie die Dienste, um die Konfiguration von Greylisting abzuschließen:
#
service obspamd restart
#
service spamlogd start
Hinter den Kulissen führen die
spamdb-Datenbank und
spamlogd wesentliche Aufgaben der
Greylisting-Funktion aus. spamdb
ist die Schnittstelle für den Administrator, der über den
Inhalt der Datenbank /var/db/spamdb
Blaklists, Whitelists und Greylists verwaltet.
Dieser Abschnitt beschreibt die Verwendung von
block-policy
, scrub
und antispoof
, mit denen das Verhalten
des Regelsatzes weiter optimiert werden kann.
Die Option block-policy
kann im
Teil options
des Regelwerks konfiguriert
werden, vor den Umleitungen und den eigentlichen
Filterregeln. Diese Option legt fest, welche Rückmeldung
PF an einen geblockten Rechner
sendet. Es existieren zwei mögliche Werte:
drop
verwirft das Paket ohne Rückmeldung
und return
gibt eine Statusmeldung, wie
etwa Connection refused
zurück.
Die Voreinstellung ist drop
. Geben
Sie den gewünschten Wert ein, um die
block-policy
-Richtlinie zu ändern:
set block-policy return
scrub
ist ein Schlüsselwort in
PF, das die Paket-Normalisierung
aktiviert. Dieser Prozess fügt fragmentierte Pakete wieder
zusammen und blockt TCP-Pakete mit
ungültigen Flag-Kombinationen. Ein aktiviertes
scrub
bietet einen gewissen Schutz gegen
Angriffe, die auf die falsche Handhabung von fragmentierten
Paketen aufbauen. Es stehen viele Optionen zur Verfügung,
jedoch sollte die einfachste Form für die meisten
Konfigurationen ausreichend sein:
scrub in all
Einige Dienste, wie beispielsweise NFS, erfordern eine bestimmte Handhabung von fragmentierten Paketen. Weitere Informationen finden Sie unter https://home.nuug.no/~peter/pf/en/scrub.html.
Dieses Beispiel fügt fragmentierte Pakete wieder zusammen, löscht das „do not fragment“-Bit und setzt die maximale Segmentgröße auf 1440 Bytes:
scrub in all fragment reassemble no-df max-mss 1440
Der antispoof
-Mechanismus bietet
einen Schutz gegen gefälschte
IP-Adressen. Dabei werden hauptsächlich
Pakete verworfen, die auf der falschen Schnittstellen
ankommen.
Folgende Regeln verwerfen gefälschte Adressen, wenn sie aus dem Internet oder dem lokalen Netzwerk stammen:
antispoof for $ext_if antispoof for $int_if
Sogar bei einem richtig konfigurierten NAT-Gateway müssen Sie vielleicht die Fehlkonfiguration anderer Personen ausgleichen. Ein typischer Fehler besteht darin, nicht-routebare Adressen ins Internet zu lassen. Da der Verkehr von nicht-routebaren Adressen Teil eines DoS-Angriffs sein kann, sollten Sie in Betracht ziehen, diesen Verkehr explizit an der externen Schnittstelle des Netzwerks zu blockieren.
In diesem Beispiel wird ein Makro erstellt, das die nicht-routebaren Adressen enthält. Datenverkehr von und zu diesen Adressen wird dann an der externen Schnittstelle des Gateways verworfen.
martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \ 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, \ 0.0.0.0/8, 240.0.0.0/4 }" block drop in quick on $ext_if from $martians to any block drop out quick on $ext_if from any to $martians
Unter FreeBSD kann ALTQ zusammen mit PF benutzt werden, um Quality of Service (QoS) bereitzustellen. Sobald ALTQ aktiviert ist, können Warteschlangen definiert werden, mit denen Sie die Priorität für ausgehende Pakete festlegen können.
Bevor Sie ALTQ aktivieren, sollten Sie altq(4) lesen und sicherstellen, das der Treiber der Netzwerkkarte diese Funktion unterstützt.
ALTQ steht nicht als ladbares Kernelmodul zur Verfügung. Wenn die Netzwerkkarte des Systems ALTQ unterstützt, erstellen Sie nach den Anweisungen in Kapitel 8, Konfiguration des FreeBSD-Kernels einen angepassten Kernel. Als erstes muss ALTQ aktiviert werden. Zudem ist mindestens eine weitere Option nötig, um den Algorithmus für die Warteschlange zu bestimmen:
options ALTQ options ALTQ_CBQ # Class Based Queuing (CBQ) options ALTQ_RED # Random Early Detection (RED) options ALTQ_RIO # RED In/Out options ALTQ_HFSC # Hierarchical Packet Schedule (HFSC) options ALTQ_PRIQ # Priority Queuing (PRIQ)
Die folgenden Algorithmen stehen zur Verfügung:
Class Based Queuing (CBQ) erlaubt es, die Bandbreite einer Verbindung in verschiedene Klassen oder Warteschlangen zu unterteilen, um die Priorität von Datenpaketen basierend auf Filterregeln zu beeinflussen.
Random Early Detection (RED) wird eingesetzt, um eine Überlastung des Netzwerks zu vermeiden. Dazu ermittelt RED die Größe der Warteschlange und vergleicht diesen Wert mit den minimalen und maximalen Grenzwerten der Warteschlange. Ist die Warteschlange größer als das erlaubte Maximum, werden alle neuen Pakete nach dem Zufallsprinzip verworfen.
Random Early Detection In and Out (RIO). Dieser Modus verwaltet mehrere Warteschlangen durchschnittlicher Größe mit mehreren Schwellwerten, eine für jedes QoS-Level.
Hierachical Fair Service Curve Packet Scheduler (HFSC) wird in http://www-2.cs.cmu.edu/~hzhang/HFSC/main.html beschrieben.
Priority Queuing (PRIQ) lässt den Verkehr einer Warteschlange mit höherer Priorität zuerst durch.
Weitere Informationen über diese Algorithmen und Beispiele
für Regelsätze finden Sie in den
OpenBSD Archiven
.
Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an
<de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an
<de-bsd-translators@de.FreeBSD.org>.