Praktické rady pro zabezpečení (nejen) SSH III
V dnešním díle budu v miniseriálu o zabezpečení SSH pokračovat, avšak tentokrát proberu nástroje a metody, které pomohou ochránit i jiné služby než SSH. Představím nástroj Fail2ban a proberu techniku zvanou port knocking.
Fail2ban je kolegou v minulém díle představeného nástroje Denyhosts. Zatímco Denyhosts je zaměřen výhradně na ochranu SSH prostřednictvím hosts.deny
, Fail2ban je zaměřen obecněji a dokáže ochránit nejenom SSH, ale i řadu dalších služeb. Umožňuje dokonce plné přizpůsobení své činnosti čili není problém si přidat novou hlídanou událost a případnou reakci na ni. Stejně tak je možné přizpůsobit výchozí nastavení.
V Debianu naleznete konfiguraci nástroje Fail2ban v adresáři /etc/fail2ban
. Základní nastavení naleznete v konfiguračním souboru jail.conf
, nicméně není doporučováno jej modifikovat přímo, ale změny zapsat do souboru /etc/fail2ban/jail.local
. Asi to nejdůležitější bude whitelist IP adres, u kterých nechcete přístup omezovat (abyste si server omylem na dálku "nezamkli", nebo to místo vás neprovedl útočník):
ignoreip = 127.0.0.1 10.0.0.0/8
Jednotlivé IP adresy a rozsahy jsou odděleny mezerou. Zbylé dvě z klíčových voleb jsou bantime
, tj. doba, po kterou bude útočící IP adresa zablokována (v sekundách), a maxentry
, tj. počet povolených pokusů, po jejichž překročení bude daná IP adresa zablokována:
bantime = 600
maxretry = 3
Toto jsou výchozí nastavení, která budou použita, není-li pro danou chráněnou službu specifikována jiná hodnota. Níže v konfiguračním souboru pak naleznete jednotlivé chráněné služby, u kterých jsou tyto parametry obvykle přizpůsobeny (u SSH je ve výchozím nastavení povoleno 6 pokusů o přihlášení). Anatomii nastavení jednotlivých chráněných služeb demonstruji na příkladu:
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
SSH je u Fail2ban jediná aktivní chráněná služba, ostatní musíte aktivovat úpravou volby enabled
, která musí být nastavena na true
, má-li služba být aktivní. Dále následuje port, který bude pro danou IP adresu zablokován - ssh
označuje port 22, all
pak všechny porty. Výchozí akce pro zablokování dané IP adresy zde není specifikována, tudíž je použita výchozí akce iptables-multiport
. Pokud se podíváte do adresáře/etc/fail2ban/action.d
, naleznete soubor iptables-multiport.conf
, který tuto akci řídí. Tato akce zablokuje danou IP adresu pomocí nástroje iptables
, vytvořením příslušného pravidla. Za dobu specifikovanou ve volbě bantime
toto pravidlo vymaže a z dané IP adresy se může na SSH opět přistupovat.
Fail2ban je parser logů úplně stejně jako nástroj Denyhosts. Volba filter
označuje filtr, který se má u dané služby použít, a volba logpath
pak specifikuje umístění souboru s příslušným logem. Samotný filtr pak naleznete v adresáři /etc/fail2ban/filter.d
ve stejnojmenném souboru s příponou .conf
. Filtr je tvořen sadou regulárních výrazů. Pokud budete používat nástroj Fail2ban a budete specifikovat vlastní filtr, buďte opatrní a nezapomeňte na dříve zmiňovanou hrozbu v podobě log injection.
Fail2ban má přednastavená pravidla pro ochranu řady dalších služeb - namátkou Apache, tři nejpoužívanější FTP servery, Postfix a Courier autentikační démon. Ty můžete použít bez nutnosti si příslušná řešení a pravidla nastavit ručně.
Fail2ban démona můžete řídit ručně z příkazové řádky, pomocí nástroje fail2ban-client
. Takto si můžete nechat vypsat stav chráněných služeb:
debian:~# fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: ssh
Zde vidíte pouze jediný "jail", tedy chráněnou službu, a sice ssh
. Stav jednotlivých služeb si můžete nechat vypsat podrobněji:
debian:~# fail2ban-client status ssh
Status for the jail: ssh
|- filter
| |- File list: /var/log/auth.log
| |- Currently failed: 1
| `- Total failed: 94
`- action
|- Currently banned: 2
| `- IP list: 77.93.17.145 141.152.17.15
`- Total banned: 5
Zde můžete vidět celkový počet selhaných pokusů o přihlášení (94), počet momentálně blokovaných IP adres (2) i jejich seznam (podotýkám, že IP adresy ve výpisu jsou smyšlené, nejedná se o skutečné útočníky) a celkový počet zablokovaných adres (5).
Pomocí tohoto nástroje je možné činnost Fail2ban precizně řídit z příkazové řádky, jednotlivé chráněné služby je možné odebírat, přidávat či konfigurovat nové. Více se dozvíte v dokumentaci.
Jisté zabezpečení SSH může poskytnout modul Netfiltru limit
. Tento modul umožňuje omezit počet spojení směřujících na SSH port. Jeho použití je lehce spekulativní, protože neumí brát v úvahu počet spojení z konkrétních IP adres. Přesto může v některých případech pomoci, pokud není k dispozici nic jiného:
iptables -N ssh
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ssh
iptables -A ssh -s 1.2.3.4 -j ACCEPT
iptables -A ssh -s 10.0.1.0/24 -m limit --limit 2/sec --limit-burst 20 -j ACCEPT
iptables -A ssh -m limit --limit 5/min --limit-burst 10 -j ACCEPT
iptables -A ssh -j DROP
Tato ukázka využívá stavový firewall, tzn. filtrují se pouze žádosti o nová spojení, existující spojení nebudou omezena. Veškerá nová spojení v tomto případě půjdou do řetězce ssh, ve kterém je nejprve povolena IP adresa 1.2.3.4
, na kterou se žádná omezení vztahovat nebudou. Dále je specifikován rozsah vnitřní sítě10.0.1.0/24
, který je omezen volněji, ostatní pokusy o připojení k SSH jsou pak omezeny přísněji. Poslední pravidlo zahodí jakýkoliv paket, který omezením nevyhoví.
Samotné omezení pomocí modulu limit
funguje tak trochu jako revolver, kde --limit-burst
představuje počet komor a --limit
představuje dobu, za kterou se obnoví jeden náboj. Každý paket, který projde tímto pravidlem, pak "vystřelí" jeden náboj. Pokud dojdou náboje, paket příslušnému pravidlu nevyhoví a pokračuje v řetězu dál. V prvním uvedeném příkladě je počet komor 20 a doba obnovy jednoho náboje 0.5 sekundy (obnoví se dvakrát za sekundu), ve druhém je počet komor 10 a doba obnovy je 12 sekund (obnoví se 5krát za minutu).
Zásadní nevýhody tohoto přístupu jsou dvě. V první řadě, jakýkoliv útok na SSH vyvolá Denial of Service dané služby. Můžete specifikovat whitelist (jako v příkladu výše), takže se pořád budete moci připojit z jistých IP adres, ale pro případné klienty, kteří nejsou ve výjimkách, to znamená nemožnost se připojit. Tento přístup se tedy hodí spíše tam, kde mají k SSH přístup pouze administrátoři.
Druhou nevýhodou je absence přehledu o úspěšnosti pokusu o přihlášení - tato pravidla počítají pouze průchozí pakety bez ohledu na to, zdali patří spojením, která se úspěšně autentikují vůči SSH serveru, nebo spojením, která nepředloží platné autentikační údaje.
Port knocking je další z lehce kontroverzních záležitostí, alespoň ve své čisté podobě. V zásadě funguje tak, že jistý démon naslouchá přímo na síti (tzn. nezávisle na firewallu), přičemž hledá předem jisté definované sekvence paketů přicházející z nějaké IP adresy. Pokud některou ze sekvencí uvidí, provede nějakou akci, tzn. pustí pod rootem nějaký příkaz a jako parametr mu předá zdrojovu IP adresu daných paketů. Největší problém port knockingu v této podobě spočívá v tom, že útočník naslouchající na síti (ať už blízko na straně serveru nebo blízko na straně klienta) může danou sekvenci odposlechnout a zreprodukovat. Toto se samozřejmě dá vyřešit, a to jedním ze dvou způsobů, které uvedu níže.
Démon knockd
je tím nejobvyklejším port knocking démonem. K dispozici spolu s ním je i klient, který umožňuje na porty "klepat". V Debianu je knockd
po instalaci neaktivní a čeká na úpravu hlavního konfiguračního souboru /etc/knockd.conf
, po kterém můžete démon povolit úpravou /etc/default/knockd
a spustit. Samotná konfigurace akce vypadá takto:
[fwDown]
sequence = 7001:tcp,8205:tcp,9050:udp
seq_timeout = 5
command = /etc/init.d/iptables stop
tcpflags = syn
Sekvence portů je poměrně jasně definovaná v položce sequence
- očekávají se tři pakety. TCP paket na port 7001 následovaný TCP paketem na port 8205 následovaný UDP paketem na port 9050. TCP pakety pak musí mít příznak SYN (specifikováno v položce tcpflags
. Příslušná sekvence musí proběhnout během 5 vteřin (viz položka seq_timeout
). Pokud knockd tedy takovou sekvenci paketů objeví, provede příkaz specifikovaný v položce command
. Tento naznačený příkaz slouží k zastavení firewallu (třeba pokud byste se omylem "zamkli" při ruční manipulaci s firewallem) - v Debianu ale nebude fungovat, protože Debian nemá ve výchozí instalaci k dispozici skript pro iptables
.
Samotná ochrana SSH může vypadat třeba takto:
[opencloseSSH]
sequence = 2022:udp,3303:tcp,4440:udp,5225:udp
seq_timeout = 2
tcpflags = syn,ack
start_command = /usr/sbin/iptables -A INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT
cmd_timeout = 5
stop_command = /usr/sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 22 -j ACCEPT
Tato ukázka je již poněkud šťavnatější. Je zde definována sekvence čtyřech portů, jejíž timeout je nastaven na dvě vteřiny, a jsou specifikovány dva příkazy - start_command
a stop_command
. První z příkazů otevře SSH port pro danou IP adresu, druhý dané pravidlo z firewallu vymaže. Doba mezi provedením obou příkazů se řídí položkou cmd_timeout
, která je v tomto případě nastavena na 5 sekund. Předpokladem fungování této ukázky je kompletní ochrana SSH firewallem - kromě explicitních výjimek musí být port SSH firewallem uzavřený.
Problémem těchto sekvencí je, že se dají poměrně snadno odposlechnout. Když ne někde blízko serveru, tak určitě v rámci sítě, ze které se správce na server hlásí (nezabezpečené bezdrátové sítě tomuto problému v dnešní době dávají mnohem větší rozměr). Je jasné, že k obecnému zvýšení bezpečnosti povede i tento postup - spektrum subjektů, které mohou danou sekvenci odposlechnout, bude podstatně menší než celý Internet klepající na váš otevřený SSH port. Na stranu druhou, dokud je sekvence předem daná a opakuje se, nelze předpokládat, že se k SSH přeci jen nedostane někdo nepovolaný (i když, pak máte samozřejmě stále k dispozici standardní zabezpečovací mechanismy v rámci SSH - včetně nutnosti se na server přihlásit platným jménem a heslem nebo klíčem).
Jedno z řešení tohoto problému umí i knockd
, a sice tzv. sekvence na jedno použití (položkaOne_Time_Sequences
, jejímž parametrem je soubor s řadou sekvencí). To znamená, že se nedefinuje jedna sekvence, ale celá řada sekvencí, přičemž po použití aktuální sekvence dojde k ukončení její platnosti a server bude očekávat následující sekvenci. Problémem této metody je nutnost synchronizace sekvencí na všech klientech a čas od času nutnost znovu vygenerovat nové sekvence. Bohužel mi není znám jiný způsob, jak si nechat sekvence pro knockd
vygenerovat, než si k tomu napsat vlastnískript.
Jinou možností řešit výše uvedený problém je prostřednictvím SPA, tj. single packet authorization, kde se ověření provádí jediným paketem za asistence asymetrického šifrování a GnuPG. Součástí SPA paketů jsou náhodná data, která zajišťují unikátnost každého paketu a neopakovatelnost. Tuto techniku bohužel knockd
neumí, umí ji nástroj fwknop
, který není k dispozici v repositářích momentální stabilní verze Debianu, nicméně bude k dispozici v příštím stabilním vydání. Tato technika spolu s tímto nástrojem byly popsány podrobněji v jednom z odkazů pod článkem.