Aktivní zabezpečení SSH na úrovni firewallu
Pokročilejší techniku zabezpečení SSH na úrovni firewallu představuje následující řešení, které tvoří jistou obdobu Denyhosts a Fail2ban, i když stále zde platí, že firewall nemůže zjistit, bylo-li dané přihlášení úspěšné, či nikoliv. Nutností je v tomto případě dostupnost jaderného modulu ipt_recent (v distribučním jádře Debianu tento modul k dispozici je). Příslušná pravidla vypadají zhruba takto:
1. iptables -N ssh 2. iptables -A ssh -s 1.2.3.4 -j ACCEPT 3. iptables -A ssh -m recent --update --seconds 15 --hitcount 5 --name SSH -j DROP 4. iptables -A ssh -m recent --set --name SSH -j ACCEPT 5. iptables -A ssh -j ACCEPT 6. iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ssh
Pochopit tento příklad je asi trošku obtížnější. Pokusy o připojení k SSH jsou směřovány do řetězce s názvem "ssh" (řádek 6). V tomto řetězci je nejprve povolen přístup z IP adresy 1.2.3.4
(řádek 2). Na řádku 4 je každý procházející paket zařazen do mechanismu modulu recent, a sice do jeho vlastního řetězce s názvem SSH, a propuštěn (tj. povolen). Třetí řádek je pak jádro celého mechanismu. Byla-li daná zdrojová IP adresa procházejícího paketu viděna vícekrát než 5krát za 15 sekund, je zařazena na blacklist a paket je zahozen. Pokud z dané IP adresy nepřijde žádná další žádost o pokus o připojení k SSH během 15 sekund, je daná IP adresa vyjmuta z blacklistu a může se znovu pokusit o přihlášení. Pokud z této IP adresy přijde další žádost, zatímco je v blacklistu, paket je zahozen a počítá se znovu od nuly.
Trošku komplexnější příklad může vypadat takto:
iptables -N ssh-blacklist iptables -A ssh-blacklist -m recent --name blacklist --set iptables -A ssh-blacklist -m limit --limit 1/minute --limit-burst 100 -j LOG --log-prefix "iptables ssh-blacklist: " iptables -A ssh-blacklist -j DROP iptables -N ssh-whitelist iptables -A ssh-whitelist -s 1.2.3.4 -j ACCEPT iptables -A ssh-whitelist -j RETURN iptables -N ssh iptables -A ssh -j ssh-whitelist iptables -A ssh -m recent --update --name blacklist --seconds 43200 --hitcount 1 -j DROP iptables -A ssh -m recent --set --name short iptables -A ssh -m recent --set --name long iptables -A ssh -m recent --update --name short --seconds 15 --hitcount 5 -j ssh-blacklist iptables -A ssh -m recent --update --name long --seconds 3600 --hitcount 30 -j ssh-blacklist iptables -A ssh -j ACCEPT iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ssh
Zde vidíte tři řetězce, řetězec ssh
, kam směřují nová spojení s portem 22, dále řetězec ssh-whitelist
, kde jsou specifikovány IP adresy a rozsahy, které mají být povoleny bez filtrování (v tomto případě je to jediná adresa - 1.2.3.4
). Řetězec ssh-blacklist
provádí dvě podstatné úlohy. Jednak zařazuje danou IP adresu na blacklist a příslušný paket zahazuje, ale ještě před tím, než paket zahodí, jej zaloguje. Zde vidíte modul limit
, který jsem představil výše. V tomto případě omezuje počet hlášek v logu na průměrně jednu za minutu (s možností najednou pojmout až 100 hlášek). Podstatné je, že do tohoto řetězce se příslušný paket dostane pouze jednou, a sice když je na blacklist zařazen - jinak ho zahazuje první "recent" pravidlo v řetězci ssh
. Pro blacklist jsou stanovena dvě různá časová pásma, a sice 5 spojení za 15 sekund a 30 spojení za hodinu (3600 sekund). Pokud se nějaká IP adresa pokusí o více spojení za daný časový úsek, bude zařazena na blacklist. Doba, po kterou pak v blacklistu zůstane, je minimálně 1 den (43200 sekund). Daná IP adresa bude vyjmuta, pokud se během 1 dne od zařazení do blacklistu už nepokusí o přístup k SSH. Pokud to zkusí znovu během této doby, počítadlo se vynuluje a začíná se znovu.
Jak už bylo řečeno, modul recent nebere v úvahu úspěch či neúspěch pokusu o přihlášení, pouze počet průchozích paketů za jednotku času. Oproti modulu limit
má však podstanou výhodu v tom, že počítadla paketů jsou specifická pro každou zdrojovou IP adresu průchozího paketu. To znamená, že pokud bude útočník útočit z jedné IP adresy, ta bude brzy zablokována, ale přístup odjinud bude fungovat normálně.
Uznávám, že modul recent
je trošku "vyšší dívčí", čemuž bohužel napomáhá i lehký nedostatek podrobnější dokumentace. Popis jednotlivých voleb a základní princip však lze pochopit jednak z výše odkazované dokumentace, a pak z manuálové stránky nástroje iptables
.
scponly
Posledním nástrojem, který v rámci tohoto miniseriálu představím, je scponly
. Jelikož SSH a SCP jdou ruku v ruce, může se stát, že v některých případech budete chtít, aby měl některý váš uživatel možnost přes SSH/SCP kopírovat soubory, ale současně aby se nemohl dostat k shellu a pouštět příkazy. A právě k tomu je určen nástroj scponly
.
Po instalaci stejnojmenného balíčku stačí jediný jednoduchý krok - vyměnit výchozí shell uživatele za scponly
, takto:
usermod -s /usr/bin/scponly uzivatel
Z bezpečnostních důvodů je nutné, aby daný uživatel neměl právo zápisu do svého domovského adresáře (aby nemohl upravovat konfigurační soubory v .ssh
a potenciálně si tak otevřít vrátka k shellu):
chown root:root /home/uzivatel chmod 755 /home/uzivatel
V rámci tohoto nastavení přesto vyvstává minimálně jeden další potenciální problém - uživatel může v tomto případě stále cestovat v adresářové struktuře mimo svůj domovský adresář. Pokud chcete zabránit i tomuto, je třeba využít chroot
variantu scponly
. Za tímto účelem je nejprve potřeba tuto verzi povolit:
dpkg-reconfigure scponly
Zde musím upozornit na to, že v takovém případě scponly
získá setuid
bit a bude spouštěn s právy uživatele root
. Případná zranitelnost v scponly
pak může mít katastrofální dopad (útočník získá rootovská oprávnění). Dalším krokem je užití pomocného skriptu v adresáři /usr/share/doc/scponly/setup_chroot
s názvem setup_chroot.sh
. Tento skript je před použitím třeba rozbalit:
cd /usr/share/doc/scponly/setup_chroot gzip -d setup_chroot.sh.gz chmod u+x setup_chroot.sh ./setup_chroot.sh
Skript za vás vytvoří uživatele, zkopíruje všechny nutné nástroje a knihovny do chrootu, zajistí úpravu práv domovského adresáře uživatele a vytvoří adresář, kam bude mít daný uživatel právo k zápisu. Naneštěstí, v Debianu Lenny tento skript neprovede jednu velmi důležitou operaci, a sice vytvoření /dev/null
v chrootu, což je třeba provést ručně:
mkdir /home/uzivatel/dev cp -a /dev/null /home/uzivatel/dev/