[Wstecz: Tabele] [Spis treści] [Dalej: Translacje adresów (NAT)]
Reguły filtrujące określają kryteria według których podejmowana jest konkretna akcja wobec pakietu: przepuść (ang. pass) lub blokuj (ang. block). Reguły filtrujące są porównywane sekwencyjnie, od pierwszej do ostatniej. Z wyjątkiem sytuacji, gdy pakiet pasuje do reguły ze słowem kluczowym quick, pakiety są porównywane z wszystkimi regułami filtrującymi zanim ostateczna akcja zostanie podjęta. Ostatnia pasująca reguła jest "zwycięzcą" i decyduje o podjętej akcji. Jeśli na początku zestawu reguł znajduje się bezwarunkowe pass all, wówczas wszystkie pakiety, które nie pasowały do żadnej z reguł, będą przepuszczane zgodnie z akcją pass.
action [direction] [log] [quick] [on interface] [af] [proto protocol] \
[from src_addr [port src_port]] [to dst_addr [port dst_port]] \
[flags tcp_flags] [state]
Aby wprowadzić domyślną politykę blokowania pierwsze dwie reguły powinny wyglądać tak:
block in all
block out all
Spowoduje to blokowanie całego ruchu na wszystkich interfejsach w obu kierunkach.
Kilka przykładów:
# Przepuść ruch na dc0 z sieci lokalnej, 192.168.0.0/24,
# zmierzający do 192.168.0.1. Przepuść także cały powracający
# do tej sieci ruch na dc0.
pass in on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24
# Przepuść ruch TCP z zewnątrz na fxp0 zmierzający do serwera www.
# Nazwa interfejsu, fxp0, jest użyta jako adres docelowy, więc
# pakiety będą pasować do tej reguły jedynie jeśli są przeznaczone
# dla tej maszyny OpenBSD.
pass in on fxp0 proto tcp from any to fxp0 port www
Źle:
block in on fxp0 proto tcp from any to any port ssh
pass in all
W tym przypadku, linia block może być porównywana, ale nigdy nie będzie miała żadnego efektu, ponieważ po niej znajduje się linia, która wszystko przepuszcza.
Lepiej:
block in quick on fxp0 proto tcp from any to any port ssh
pass in all
Te reguły są porównywane nieco inaczej. Jeśli linia block pasuje, dzięki opcji quick, pakiet będzie zablokowany, a reszta reguł tego zestawu będzie zignorowana.
Śledzenie stanów ma wiele zalet, włączając uproszczenie zestawu reguł i lepszą wydajność filtrowania pakietów. PF jest w stanie dopasowywać pakiety poruszające się w obu kierunkach danego połączenia, co oznacza, że reguły przepuszczające powracający ruch nie są potrzebne. A ponieważ pakiety pasujące do połączenia stanowego nie przechodzą zestawu reguł, czas zużywany na przetwarzanie tych pakietów może być bardzo znacząco zmniejszony.
Gdy reguła tworzy stan, pierwszy pakiet pasujący do niej tworzy "połączenie stanowe" pomiędzy nadawcą i odbiorcą. Wówczas, nie tylko pakiety pochodzące od nadawcy, zmierzające do odbiorcy, ale i pakiety odbiorcy, skierowane do nadawcy pasują do reguły i nie są sprawdzane przez zestaw reguł filtrujących.
Począwszy od OpenBSD 4.1, wszystkie reguły automatycznie tworzą stany w tabeli stanów gdy pakiet pasuje do danej reguły. We wcześniejszych wersjach OpenBSD reguła filtra musiała zawierać opcję keep state.
Przykładowo, korzystając z OpenBSD 4.1 i późniejszych:
pass out on fxp0 proto tcp from any to any
Dla OpenBSD 4.0 i wcześniejszych natomiast:
pass out on fxp0 proto tcp from any to any keep state
Reguły te zezwalają na wychodzenie ruchu TCP na interfejsie fxp0 i przepuszczają ruch powrotny pakietów stanowiących odpowiedź. Śledzenie stanów poza swoją funkcjonalnością, zapewnia także znaczący wzrost wydajności firewalla, ponieważ wyszukania stanów są dużo szybsze niż porównywanie pakietu z zestawem reguł filtrujących.
Opcja modulate state działa podobnie do keep state z tą różnicą, że odnosi się jedynie do pakietów TCP. Przy użyciu modulate state, Inicjujący Numer Sekwencyjny (ISN) wychodzącego połączenia jest losowy. Jest to przydatne do ochrony połączeń nawiązanych przez różne systemy operacyjne, które nie najlepiej radzą sobie z generowaniem numeru ISN. Począwszy od OpenBSD 3.5, opcja modulate state może być używana w regułach, które odnoszą się także do innych niż TCP protokołów.
Śledź stan wychodzących pakietów TCP, UDP i ICMP oraz generuj ISN dla TCP:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
Inną zaletą śledzenia stanów jest to, iż odpowiedni ruch ICMP będzie przepuszczany przez firewall. Na przykład, jeśli połączenie TCP przechodzi przez firewall, jest ono śledzone stanowo i w momencie gdy nadejdzie komunikat ICMP "gaszący źródło" (ang. source-quench) odwołujący się do tego połączenia, będzie on dopasowany do odpowiedniego wpisu stanowego i przepuszczony przez firewall.
Zakres (ang. scope) wpisów w tabeli stanów jest globalnie kontrolowany poprzez opcje czasu wykonywania state-policy, niemniej można go określić dla poszczególnych reguł indywidualnie poprzez słowa kluczowe reguł śledzenia stanów: if-bound, group-bound i floating. Słowa kluczowe użyte dla pojedynczej reguły mają to samo znaczenie co w przypadku globalnej polityki stanów state-policy. Przykład:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
Reguła ta narzuca wymóg, aby pakiety które pasują do tej reguły były przekazywane przez interfejs fxp0.
Proszę zwrócić uwagę, że reguły nat, binat, i rdr bezwarunkowo tworzą stan dla pasujących połączeń tak długo, jak dane połączenie jest przekierowywane przez daną regułę.
Opcje podawane są w nawiasach, zaraz po użyciu jednego ze słów kluczowych (keep state, modulate state, or synproxy state). Opcje oddzielone są przecinkami. W OpenBSD 4.1 i późniejszych, opcja keep state, jest wstawiana domyślnie do wszystkich reguł filtra. Pomimo tego, używając opcji dla filtrowania stanowego, konieczne jest użycie jednego ze słów kluczowych przed określonymi opcjami.
Przykład:
pass in on $ext_if proto tcp to $web_server \
port www keep state \
(max 200, source-track rule, max-src-nodes 100, max-src-states 3)
Powyższy przykład powoduje:
Dodatkowe ograniczenia mogą być ustawione dla śledzenia połączeń TCP dla których zakończyła się negocjacja protokołu.
Każda z tych opcji automatycznie przywołuje opcję source-track rule, oraz jest niekompatybilna z source-track global.
Ponieważ opcje te dotyczą tylko połączeń TCP które zakończyły negocjację, bardziej agresywne zachowania mogą być użyte dla przestępczego adresu IP.
Przykład:
table <abusive_hosts> persist
block in quick from <abusive_hosts>
pass in on $ext_if proto tcp to $web_server \
port www flags S/SA keep state \
(max-src-conn 100, max-src-conn-rate 15/5, overload <abusive_hosts> flush)
Powyższe reguły wykonują:
Aby PF sprawdzał flagi TCP podczas przetwarzania reguł filtrujących wykorzystywane jest słowo kluczowe flags. Jego składnia jest następująca:
flags check/mask
flags any
Część mask mówi PF aby sprawdzać jedynie podane flagi, a część check określa która flaga(i) powinny być "ustawione" w nagłówku, aby dopasowanie miało miejsce. Użycie klucza any zezwala na ustawienie dowolnej kombinacji flag w nagłówku.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
Powyższa reguła przepuszcza ruch TCP z ustawioną jedynie flagą SYN, biorąc pod uwagę tylko flagi SYN i ACK. Pakiet z flagami SYN i ECE będzie pasował do powyższej reguły, jednak pakiet z SYN i ACK lub tylko ACK już nie.
W OpenBSD 4.1 i późniejszych, domyślne flagi stosowane od reguł TCP to flags S/SA. W połączeniu z domyślnym dla OpenBSD 4.1 zachowaniem keep state w regułach filtra, poniższe dwie linie są równoważne:
pass out on fxp0 proto tcp all flags S/SA keep state
pass out on fxp0 proto tcp all
Każda reguła do której pasuje pakiet TCP z ustawiona flagą SYN i wygaszona flagą ACK utworzy odpowiedni stan. Domyślne zachowanie może być zmienione poprzez użycie opcji flags, jak to zostało pokazane wcześniej.
W OpenBSD 4.0 i wcześniejszych flagi domyślne nie były stosowane w regułach filtra. Każda reguła musiała mieć określone pasujące flagi oraz bezpośrednio użytą opcję keep state.
pass out on fxp0 proto tcp all flags S/SA keep state
Przy korzystaniu z flag trzeba być bardzo ostrożnym - należy rozumieć
co się robi i dlaczego, no i należy uważać na rady innych,
ponieważ często są one błędne. Niektórzy np. sugerują tworzenie stanu
"jedynie gdy flaga SYN jest ustawiona, i żadna inna". Taka reguł
wyglądała by tak:
. . . flags S/FSRPAUEW to zły pomysł!!
W teorii, tworzy się połączenie stanowe na początku sesji TCP, a sesja powinna rozpocząć się od flagi SYN, i żadnej innej. Problem polega na tym, że niektórzy użytkownicy rozpoczynają połączenia wraz z flagą ECN, i będą odrzuceni przez taką regułę. Dużo lepszą praktyką jest nie określanie żadnych flag i pozwolenie PF-owi by zastosował domyślne flagi do twoich reguł. Jeśli naprawde chcesz sam określić swoje flagi poniższa kombinacja powinna być bezpieczna:
. . . flags S/SAFR
Jest to praktyczne i bezpieczne. Jeśli ruch podlega normalizacji scrub, wówczas można nie sprawdzać także flag FIN i RST. Normalizacja powoduje, że PF porzuca nadchodzące pakiety z nieprawidłową kombinacja flag (taką jak SYN i FIN lub SYN i RST) a także normalizuje potencjalnie niejasne kombinacje (takie jak SYN i FIN).
Domyślnie gdy klient nawiązuje połączenie TCP z serwerem PF przepuszcza pakiety związane z "potrójnym uzgodnieniem" (ang. handshake) pomiędzy dwoma uczestniczącymi końcami gdy tylko nadejdą. PF ma jednak zdolność do pośredniczenia (ang. to proxy) w "potrójnym uzgodnieniu". Dzięki temu, to PF dokona poprawnego "potrójnego uzgodnienia" z klientem, następnie zainicjuje "potrójne uzgodnienie" z serwerem i dopiero wtedy zacznie przekazywać pakiety pomiędzy oboma węzłami. Najważniejszą korzyścią tego procesu jest to, iż żaden pakiet nie zostanie wysłany do serwera zanim klient nie dokona poprawnego "potrójnego uzgodnienia". Eliminuje to zagrożenie ataków typu "TCP SYN flood" na serwer danej usługi.
"TCP SYN proxy" jest uruchamiane przy pomocy słów kluczowych synproxy state w regułach filtrujących. Na przykład:
pass in on $ext_if proto tcp from any to $web_server port www \
flags S/SA synproxy state
Tu, połączenia do serwera WWW będą nawiązywanie za pośrednictwem "TCP SYN proxy" przez PF.
Ze względu na swoje działanie, synproxy state zawiera funkcjonalności keep state i modulate state.
"SYN proxy" nie będzie działać jeśli PF jest uruchomiony na moście (ang. bridge(4)).
PF oferuje pewną ochronę przed podszywaniem się pod inne adresy poprzez słowo kluczowe antispoof:
antispoof [log] [quick] for interface [af]
Przykład:
antispoof for fxp0 inet
Gdy zestaw reguł jest ładowany, każde wystąpienie antispoof jest rozszerzane do dwóch reguł filtrujących. Zakładając, że interfejs fxp0 ma adres IP 10.0.0.1 i maskę podsieci 255.255.255.0 (np, /24), powyższa reguła antispoof byłaby przekształcona w:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
Reguły te realizują dwa zadania:
UWAGA: Reguły filtrujące, w które antispoof się przekształca będą blokować także pakiety wysyłane przez interfejs zwrotny (ang. loopback) na lokalny adres. W każdym razie najlepiej opuszczać filtrowanie pakietów na interfejsie zwrotnym, a staje się to konieczne w przypadku korzystania z reguł antispoof:
set skip on lo0
antispoof for fxp0 inet
Korzystanie z antispoof powinno być ograniczone do interfejsów, które mają przypisany adres IP. Użycie antispoof na interfejsie bez adresu IP spowoduje powstanie następujących reguł filtrujących:
block drop in on ! fxp0 inet all
block drop in inet all
Przy takich regułach istnieje ryzyko blokowania całego nadchodzącego ruchu na wszystkich interfejsach.
Od wersji OpenBSD 4.0, PF zawiera obsługę Unicast Reverse Path Forwarding (uRPF). W sytuacji gdy pakiet przechodzi przez sprawdzanie uRPF, źródłowy adres IP pakietu jest sprawdzany w tablicy routingu. Gdy znaleziony w tablicy routingu wpis dotyczący interfejsu wyjściowego jest taki sam jak interfejsu z którego pakiet właśnie nadszedł, wówczas sprawdzenie uRPF powoduje jego przepuszczenie. Gdy interfejsy nie pasują, istnieje możliwość że pakiet posiada podmieniony adres źródłowy.
Sprawdzenie uRPF moze być wykonywane poprzez użycie flagi urpf-failed w zestawie reguł filtra:
block in quick from urpf-failed label uRPF
Zwróć uwagę, że sprawdzanie uRPF ma sens tylko w środowiskach gdzie routing jest symetryczny.
uRPF dostarcza taką samą funkcjonalność jak reguły antispoof.
Pasywne rozpoznawanie systemów operacyjnych (ang. Passive OS Fingerprinting, OSFP) to sposób pasywnego rozpoznawania systemu operacyjnego zdalnego węzła na podstawie pewnych charakterystycznych cech jego pakietów TCP SYN. Informacje te mogą być wykorzystywane jako kryteria w regułach filtrujących.
PF rozpoznaje system operacyjny zdalnego węzła dzięki porównywaniu jego charakterystyk pakietów TCP SYN z plikiem zawierającym "odciski palców" (ang. fingerprints file) różnych systemów operacyjnych, którym domyślnie jest /etc/pf.os. Jeśli PF jest włączony, aktualna lista "odcisków" może być wyświetlona poniższą komendą:
# pfctl -s osfp
W regule filtrującej, rozpoznawanie "odcisków" może być określane poprzez rodzinę systemów operacyjnych, wersje lub gałąź/poziom poprawek. Każda z tych składowych jest wylistowana na wyjściu dopiero co wyżej wspomnianej komendy pfctl. Aby określić "odcisk" systemu w regule filtrującej, używamy słowa kluczowego os:
pass in on $ext_if from any os OpenBSD keep state
block in on $ext_if from any os "Windows 2000"
block in on $ext_if from any os "Linux 2.4 ts"
block in on $ext_if from any os unknown
Specjalna klasa systemów unknown pozwala dopasować pakiety, dla których "odciski" nie zostały rozpoznane.
WARTO PAMIĘTAĆ następujące fakty:
pass in quick on fxp0 all allow-opts
ext_if = "fxp0"
int_if = "dc0"
lan_net = "192.168.0.0/24"
# table containing all IP addresses assigned to the firewall
table <firewall> const { self }
# nie filtruj na interfejsie zwrotnym (loopback)
set skip on lo0
# normalizacja przychodzących pakietów
scrub in all
# ustawienie polityki domyślnego blokowania
block all
# aktywuj ochronę przed spoofing-iem na wszystkich interfejsach.
block in quick from urpf-failed
# zezwalaj na połączenia ssh z sieci lokalnej jedynie z zaufanego
# hosta - 192.168.0.15. korzystaj z "block return", aby TCP RST
# od razu było wysyłane w odpowiedzi na blokowane połączenia
# korzystaj z "quick", aby reguła nie była nadpisana przez
# znajdujące się poniżej reguły "pass"
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh
# przepuszczaj cały ruch z i do lokalnej sieci.
# reguły te utworzą wpisy w tabeli stanów zgodnie z domyślnym
# dołączeniem opcji "keep state"
pass in on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net
# wypuszczaj tcp, udp i icmp na interfejsie zewnętrznym (Internet).
# połączenia tcp będą modulowane, połączenia udp/icmp będą
# śledzone poprzez stany
pass out on $ext_if proto { tcp udp icmp } all modulate state
# zezwalaj na połączenia ssh na interfejsie zewnętrznym pod warunkiem,
# że NIE są one skierowane do firewall-a (np, nie są skierowane
# do maszyny z sieci lokalnej). twórz logi dla pakietów inicjujących
# połączenia, aby można było potem stwierdzić, kto próbował się
# połączyć. używamy "tcp syn proxy" dla nadchodzących połączeń.
# flagi domyślne "S/SA" będą automatycznie dołączane do reguł
# PF-a.
pass in log on $ext_if proto tcp from any to ! <firewall> \
port ssh synproxy state
|
[Wstecz: Tabele] [Spis treści] [Dalej: Translacje adresów (NAT)]