[Předchozí: Tabulky] [Obsah] [Další: Network Address Translation]
Filtrovací pravidla specifikují kritéria, která musí paket splnit a následnou akci, buď blokování nebo povolení, která se vykoná jakmile se najde shoda. Filtrovací pravidla jsou vykonávána sekvenčně od prvního k poslednímu. Pokud paket neodpovídá pravidlu obsahujícímu klíčové slovo quick, tak paket prochází všechna pravidla předtím než nastane finální akce. Poslední pravidlo, které odpovídá je "vítěz" a bude určovat, která akce se s paketem provede. Je zde defaultní pravidlo pass all na začátku seznamu, které znamená, že pokud paket neodpovídá žádnému filtrovacímu pravidlu, tak výsledná akce bude 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]
Pro vytvoření "default deny" filtrovací politiky stačí vytvořit tyto první dvě filtrovací pravidla:
block in all
block out all
Toto bude blokovat všechen provoz na všech rozhraních v jakémkoliv směru a odkudkoliv kamkoliv.
Některé příklady:
# Pass traffic in on dc0 from the local network, 192.168.0.0/24,
# to the OpenBSD machine's IP address 192.168.0.1. Also, pass the
# return traffic out on 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
# Pass TCP traffic in on fxp0 to the web server running on the
# OpenBSD machine. The interface name, fxp0, is used as the
# destination address so that packets will only match this rule if
# they're destined for the OpenBSD machine.
pass in on fxp0 proto tcp from any to fxp0 port www
Špatně:
block in on fxp0 proto tcp to port ssh
pass in all
V tomto případě by block řádek měl být vykonán, ale nikdy nebude mít žádný efekt, protože je následován řádkem, který propustí vše.
Lépe:
block in quick on fxp0 proto tcp to port ssh
pass in all
Tyto pravidla jsou vykonány trochu odlišně. Pokud řádek block odpovídá, tak díky volbě quick bude paket zablokován a zbytek pravidel bude ignorován.
Udržování informace o spojení má mnoho výhod včetně lehčích pravidel a lepšího výkonu filtrování paketů. PF je schopné kontrolovat pakety pohybující se v jakémkoliv směru proti záznamům ve stavové tabulce což znamená, že filtrovací pravidla, která propuští vracející se provoz nemusí být vůbec napsaná. A díky tomu, že pakety odpovídající navázaným spojení neprochází vyhodnocením pomocí pravidel, tak čas, který PF stráví správou těchto paketů může být výrazně snížen.
Když pravidlo vytváří stav, tak první paket odpovídající pravidlu vytváří "stav" mezi odesílatelem a příjemcem. Nyní nejen pakety odcházející od odesílatele k příjemci odpovídají stavovému záznamu a přeskakují průchod pravidly, ale i pakety vracející se stejnou cestou se chovají stejně.
Všechny pass pravidla automaticky vytváří stavový záznam, když paket odpovídá pravidlu. Toto může být explicitně zrušeno použítím no state volby.
pass out on fxp0 proto tcp from any to any
Toto pravidlo umožňuje jakýkoliv odchozí TCP provoz na fxp0 rozhraní a také povoluje vracející se provoz k tomuto spojení skrze firewall. Udržování informace o spojení výrazně zlepšuje výkon vašeho firewallu, protože vyhledávání stavu jsou dramaticky rychlejší v porovnání s průchodem paketu filtrovacími pravidly.
Volba modulate state funguje stejně jako keep state mimo to, že je funkční pouze pro TCP pakety. S modulate state je Initial Sequence Number (ISN) odchozího spojení randomizováno. Toto je užitečné pro ochranu spojení navazovaných některými operačními systémy, které odvádí špatnou práci při výběru ISN. Pro umožnění lehčích pravidel může být volba modulate state použita v pravidlech, která specifikují protokol jiný než TCP; v těchto případech je vyhodnocována jako keep state.
Udržování informace o spojení pro odchozí TCP, UDP a ICMP pakety a modulování TCP ISN:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state
Další výhoda udržování informace o spojení je, že související ICMP provoz bude propuštěn skrze firewall. Například když TCP spojení prochází firewallem a je o něm udržována informace o spojení a zároveň přijde ICMP source-quench zpráva odkazující na toto TCP spojení, tak bude přiřazena odpovídajícímu záznamu o stavu a propuštěna skrze firewall.
Rozsah stavového záznamu je globálně kontrolován pomocí state-policy volby za běhu a v jednotlivých pravidlech pomocí if-bound a floating klíčových slov pro stavy. Tyto klíčová slova pro jednotlivá pravidla mají stejný význam jako když se použíjí s volbou state-policy . Příklad:
pass out on fxp0 proto { tcp, udp, icmp } from any \
to any modulate state (if-bound)
Toto pravidlo nařídí, že aby pakety souhlasili se stavovým záznamem, tak musí procházet přes fxp0 rozhraní.
Volby jsou specifikovány uvnitř závorek a okamžitě po jednom z klíčových slov pro stavy (keep state, modulate state nebo synproxy state). Vícenásobné volby jsou odděleny čárkou. V OpenBSD 4.1 a pozdějších se keep state volba stala implicitně defaultní pro všechna filtrovací pravidla. Navzdory tomuto musí být při specifikaci voleb stavů jedno z klíčových slov pro stavy vždy použito ještě před těmito volbami.
Příklad pravidla:
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)
Pravidlo uvedené výše definuje následující chování:
Samostatná sada omezení může být uplatněna na stateful TCP spojení, která dokončila tzv. 3-cestný handshake.
Obě tyto volby automaticky používají source-track rule volbu a jsou nekompatibilní s source-track global.
Protože tyto limity jsou aplikovány pouze proti TCP spojením, které dokončili 3-cestný handshake, tak je možné použít mnohem agresivnější akce proti "útočícím" IP adresám.
Příklad:
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)
Toto dělá následující:
Aby PF kontroloval TCP volby paketu během vykonávání pravidla, tak se používá klíčové slovo flags s následující syntaxí:
flags check/mask
flags any
Část mask PF říká, aby kontroloval pouze specifikované volby a část check specifikuje, která volba(y) musí být "zapnuty" v záhlaví aby nastala shoda. Použití klíčového slova any umožňuje, aby jakákoliv kombinace voleb v záhlaví odpovídala.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA
pass in on fxp0 proto tcp from any to any port ssh
Protože flags S/SA je nastaveno defaultně, tak výše uvedená pravidla jsou stejná; každé z těchto pravidel propouští TCP provoz s volbou SYN nastavenou, přičemž se dívá pouze na SYN a ACK volby. Paket s volbami SYN a ECE bude odpovídat výše uvedeným pravidlům, ale paket s SYN a ACK nebo pouze ACK už ne.
Defaultní volby mohou být přepsány pomocí volby flags jak je zmíněno výše.
Je důležité být opatrný při použítí voleb -- rozumějte tomu co děláte a proč a buďte opatrní s doporučeními od lidí, protože hodně z nich je špatných. Někteří lidé doporučovali vytvořit stav "jen pokud je SYN volba nastavena a žádné jiné". Takové pravidlo může končit nějak takhle:
. . . flags S/FSRPAUEW bad idea!!
Teorie je vytvořit stav jen na začátku TCP spojení a spojení by mělo začínat s SYN volbou a žádnou jinou. Problém je, že některé systémy začínají používat ECN volbu a tak jakýkoliv systém používající ECN, který se pokusí s vámi spojit bude tímto pravidlem odmítnut. Mnohem lepší přístup je nespecifikovat vůbec žádné volby a nechat PF aplikovat defaultní volby do vašich pravidel. Pokud opravdu sami pro sebe chcete volby specifikovat, tak následující kombinace by měla být bezpečná:
. . . flags S/SAFR
I když je toto praktické a bezpečné, tak je také zbytečné kontrolovat FIN a RST volby pokud je provoz také kontrolován pomocí scrub. Scrub proces způsobí, že PF zahodí jakékoliv příchozí pakety s nelegálními kombinacemi TCP voleb (jako SYN a RST) a normalizuje potencionálně nejasné kombinace (jako SYN a FIN).
Normálně, když klient inicializuje TCP spojení k serveru, tak PF propustí handshake pakety mezi dvěma body spojení tak jak přicházejí. PF má ovšem schopnost aplikovat proxy na tyto handshake. Když handshake prochází přes tuto proxy, tak PF samotné dokončí handshake s klientem a poté vyvolá handshake se serverem a až poté propustí pakety mezi klientem a serverem. V případě TCP SYN flood útoku útočník nikdy nedokončí 3-cestný handshake, takže pakety útočníka nikdy nedojdou až na chráněný server, ale legitimní klienti handshake dokončit mohou a jsou propuštěni dále. Toto omezuje dopad podvržených TCP SYN floods na chráněnou službu, které jsou zpracovány přímo v PF. Běžné používání této volby není doporučeno, protože narušuje očekávané chování TCP protokolu v případě, kdy server nemůže zpracovat dotaz a v případech kdy je použit load balancer.
TCP SYN proxy se povoluje pomocí klíčového slova synproxy state ve filtrovacích pravidlech. Příklad:
pass in on $ext_if proto tcp to $web_server port www synproxy state
V tomto případě budou spojení k web serveru procházet přes TCP proxy v PF.
Díky tomu jak synproxy state funguje, tak také obsahuje stejnou funkcionalitu jako keep state a modulate state.
SYN proxy nebude fungovat pokud PF běží na bridge(4).
PF nabízí určitou ochranu proti podvrženým adresám pomocí klíčového slova antispoof :
antispoof [log] [quick] for interface [af]
Příklad:
antispoof for fxp0 inet
Když se pravidla nahrávají, tak jakýkoliv výskyt klíčového slova antispoof je rozšířen do dvou filtrovacích pravidel. Pokud má například rozhraní fxp0 IP adresu 10.0.0.1 a síťovou masku 255.255.255.0 (tzn., /24), tak antispoof pravidlo se rozšíří do:
block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any
Tyto pravidla splňují dvě věci:
POZNÁMKA: Filtrovací pravidla, do kterých se antispoof pravidlo také rozšíři, blokují i pakety posílané přes lokální rozhraní na lokální adresy. Je proto dobrou praxí vynechat filtrování na lokálních rozhraních. Což je dobré i tak, ale stává se to nutností při použítí antispoof pravidel:
set skip on lo0
antispoof for fxp0 inet
Použití antispoof by mělo být omezeno na rozhraní, která mají přiřazenu IP adresu. Použití antispoof na rozhraní bez IP adresy skončí filtrovacím pravidlem, které vypadá nějak takto:
block drop in on ! fxp0 inet all
block drop in inet all
S těmito pravidly je zde riziko, že bude blokován všechen příchozí provoz na všech rozhraních.
PF nabízí vlastnost - Unicast Reverse Path Forwarding (uRPF). Když paket prochází uRPF kontrolou, tak zdrojová IP adresa paketu projde kontrolou v směrovací tabulce. Pokud odchozí rozhraní nalezené v záznamu směrovací tabulky je stejné jako rozhraní přes které paket přišel, tak uRPF kontrola proběhne v pořádku. Pokud ale rozhraní nejsou stejná, tak je možné, že paket má svoji zdrojovou adresu podvrženu.
Kontrola uRPF může být na paketech vykonána pomocí klíčového slova urpf-failed ve filtrovacích pravidlech:
block in quick from urpf-failed label uRPF
Uvědomte si, že uRPF kontrola má smysl pouze v prostředí, kde se používá symetrické směrování.
uRPF poskytuje stejnou funkcionalitu jako antispoof pravidla.
Pasivní detekce operačních systémů - Passive OS Fingerprinting (OSFP) je metoda pro pasivní detekci operačního systému vzdáleného systému (počítače, serveru,...), která je založena na určitých charakteristikách, které tento systém promítne do TCP SYN paketů. Tato informace pak může být použita jako kritérium ve filtrovacích pravidlech.
PF určuje vzdálený operační systém porovnáním charakteristik TCP SYN paketu proti souboru otisků, kterým je defaultně /etc/pf.os. Jakmile je PF povolen, tak aktuální seznam otisků může být zobrazen pomocí tohoto příkazu:
# pfctl -s osfp
V rámci filtrovacího pravidla může být otisk specifikován pomocí třídy OS, verze nebo subtypu/patch verze. Každá z těchto položek je vypsána ve výstupu příkazu pfctl použitého výše. Ke specifikováni otisku ve filtrovacím pravidle je třeba použít kličové slovo os :
pass in on $ext_if proto tcp from any os OpenBSD keep state
block in on $ext_if proto tcp from any os "Windows 2000"
block in on $ext_if proto tcp from any os "Linux 2.4 ts"
block in on $ext_if proto tcp from any os unknown
Speciální třída operačního systému unknown umožňuje nastavit shodu u paketů, kde otisk OS není znám.
NEZAPOMEŇTE na následující:
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 }
# don't filter on the loopback interface
set skip on lo0
# scrub incoming packets
match in all scrub (no-df)
# setup a default deny policy
block all
# activate spoofing protection for all interfaces
block in quick from urpf-failed
# only allow ssh connections from the local network if it's from the
# trusted computer, 192.168.0.15. use "block return" so that a TCP RST is
# sent to close blocked connections right away. use "quick" so that this
# rule is not overridden by the "pass" rules below.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
to $int_if port ssh
# pass all traffic to and from the local network.
# these rules will create state entries due to the default
# "keep state" option which will automatically be applied.
pass in on $int_if from $lan_net
pass out on $int_if to $lan_net
# pass tcp, udp, and icmp out on the external (Internet) interface.
# tcp connections will be modulated, udp/icmp will be tracked
# statefully.
pass out on $ext_if proto { tcp udp icmp } all modulate state
# allow ssh connections in on the external interface as long as they're
# NOT destined for the firewall (i.e., they're destined for a machine on
# the local network). log the initial packet so that we can later tell
# who is trying to connect.
# Uncomment last part to use the tcp syn proxy to proxy the connection.
pass in log on $ext_if proto tcp to ! <firewall> \
port ssh # synproxy state
|
[Předchozí: Tabulky] [Obsah] [Další: Network Address Translation]