Hashování souboru known_hosts
Ukládání jmen známých serverů s sebou nese jistý bezpečnostní problém. Představme si situaci, kdy uživatel používá nešifrovaný SSH klíč a nějakým nedopatřením poskytne útočníkovi celý obsah adresáře ~/.ssh
. Útočník se dostane jak ke klíči, tak i k seznamu serverů, na které má klíč vyzkoušet.
Aby to neměl tak snadné, můžeme jména serverů v souboru known_hosts
jednosměrně zahashovat, tak aby nebylo možné ze seznamu zpětně vyčíst jména a adresy serverů. Zahashování stávajícího souboru provedeme takto:
$ ssh-keygen -H /home/user/.ssh/known_hosts updated. Original contents retained as /home/user/.ssh/known_hosts.old WARNING: /home/user/.ssh/known_hosts.old contains unhashed entries Delete this file to ensure privacy of hostnames
Přesně podle rady je pak třeba vymazat soubor known_hosts.old
, který obsahuje zálohu souboru před hashováním. Aby byly nové položky do souboru automaticky přidávány v hashované podobě, přidáme do uživatelského konfiguračního souboru ~/.ssh/config
nebo do globálního souboru /etc/ssh/ssh_config
direktivu:
HashKnownHosts yes
Může se stát, že budeme potřebovat v zahashovaném souboru vyhledat klíč pro konkrétní jméno serveru, nebo IP adresu. Řešením je opět nástroj ssh-keygen
:
$ ssh-keygen -F server.example.com # Host server.example.com found: line 5 type RSA |1|9G8jS4p4PRRyRHD83CEKTm5lfsg=|6Rk/zoBA5QoKTXH/xjLsA8+wamQ= ssh-rsa AAAAB…=
Je třeba poznamenat, že hashování s sebou nese i některé nevýhody. Například pokud používáte balík Bash completion, přestane fungovat doplňování jmen vzdálených serverů, které je právě závislé na obsahu souboru known_hosts
. Bezpečnostní význam hashování je zanedbatelný, pokud zároveň ukládáte historii příkazového řádku. Používáte-li bash, můžete pro zabránění zapamatování historie příkazů z rodiny SSH přidat do souboru ~/.bashrc
následující proměnnou:
export HISTIGNORE="ssh *:scp *:sftp *"
Osobně se historie ani automatického doplňování názvů serverů nehodlám vzdát, z toho důvodu hashování seznamu známých serverů nepoužívám.
Přenos proměnných prostředí
Mezi lidmi od počítačů od nepaměti existuje spor o to, zda lokalizovat či nelokalizovat uživatelské prostředí. V případě Linuxu k otázce lokalizace ještě přibyla otázka, jakou znakovou sadu používat, zda některou z rozšířených osmibitových sad znaků ISO/IEC 8859, nebo univerzální sadu znaků UTF-8 s proměnlivou délkou znaku. I při použití čistě anglického prostředí dokáže být nesprávné kódování velice nepříjemné, zejména při používání nejrůznějších TUI aplikací.
OpenSSH částečně umožňuje problémy s nesourodostí znakových sad na různých počítačích řešit. Během navazování spojení může klient přenést na server obsah proměnných prostředí, které nastavují správnou jazykovou verzi a kódování znaků. Stačí do konfiguračního souboru klienta přidat:
SendEnv LANG LC_*
Na straně serveru přidáme odpovídající volbu:
AcceptEnv LANG LC_*
Správné nastavení proměnných LANG
a LC_*
je podmínkou nutnou, nikoli však dostačující. Aby lokalizace fungovala jak má, je třeba mít na straně serveru nainstalované příslušné lokalizační soubory. To obvykle bývá splněno, příkaz locale -a
nás přesvědčí:
$ locale -a C cs_CZ cs_CZ.iso88592 cs_CZ.utf8 czech en_US en_US.iso88591 en_US.utf8 POSIX
I při správném nastavení se může stát, že se proměnné prostředí nepřenesou. Může za to obvykle některý ze skriptů, který se spouští po přihlášení uživatele, nebo modul pam_env
. Novější verze linuxových distribucí ale tímto neduhem obvykle netrpí. Některé dokonce předávání proměnných prostředí nastavují jako výchozí nastavení SSH serveru a klienta.
Interaktivní ovládání SSH klienta
Zdaleka ne všichni uživatelé OpenSSH klienta vědí, že je jej možné, podobně jako třeba telnet klienta, ovládat také interaktivně přímo během relace. Ke vstupu do interaktivního režimu slouží znak tylda (~), speciální význam má pouze, je-li zadán na novém řádku, tedy bezprostředně po stisknutí klávesy Enter.
Příkazů, které je možné interaktivně zadat, není mnoho. Kompletně je shrnuje manuálová stránka ssh(1) v sekci ESCAPE CHARACTERS. Asi nejpraktičtější je příkaz . (tečka), vyvoláme jej v jakékoli situaci postupným stisknutím kláves Enter, ~ a . (tečka). Pomocí něj je možné bezpodmínečně ukončit SSH klienta, třeba v případě, kdy ztratí spojení se serverem a jakoby přestane reagovat.
SSH klienta je také možné dočasně přerušit příkazem Ctrl+Z, zadaném opět po escape sekvenci. K přerušenému spojení se vrátíme příkazem fg
.
Pod příkazem C se skrývá příkazový řádek SSH klienta. Jeho možnosti jsou velmi omezené, shrnuje je příkaz -h
:
user@server:$ {stisknuto Enter} user@server:$ {stisknuto ~, C} ssh> -h Commands: -L[bind_address:]port:host:hostport Request local forward -R[bind_address:]port:host:hostport Request remote forward -D[bind_address:]port Request dynamic forward -KR[bind_address:]port Cancel remote forward
Příkazový řádek je tedy možné použít k navazování nových SSH tunelů, aniž by bylo nutné navazovat nové SSH spojení. Po zadání příkazu se příkazový řádek ukončí a předá konzoli opět SSH spojení, takže na konci výše uvedené ukázky je možné přímo začít zadávat příkaz pro vzdálený server. Pro získání další výzvy příkazového řádku je třeba znovu použít escape sekvenci.
Sdílené SSH spojení
V seriálu jsme již poznali, že po jednom SSH spojení je možné přenášet mnoho nezávislých relací, jako například tunelů či přesměrování. Stejně tak je možné přenášet jedním SSH spojením více terminálových sezení. OpenSSH tuto vlastnost protokolu implementuje prostřednictvím master-slave režimu. Řídicí SSH klient naváže spojení k serveru jako obyčejně, kromě toho ale vytvoří UNIXový soket. Podřízený klient pak namísto síťové komunikace s cílovým serverem komunikuje pouze prostřednictvím tohoto soketu. Podřízený klient také nijak neřeší autentizaci – tu už vyřešil master. Může-li číst a zapisovat do řídicího soketu, může otevřít terminálové sezení. Pojďme to nejprve vyzkoušet:
user@klient:$ ssh -S ~/.ssh/controlsock -M server.example.com user@server:$
Tímto příkazem jsme vytvořili řídicí spojení k serveru. V jiném terminálu zkontrolujeme, že se vytvořil soket ~/.ssh/controlsock
a otevřeme podřízené spojení:
user@klient:$ ssh -S ~/.ssh/controlsock whatever user@server:$
Místo slova whatever můžeme použít skutečně cokoli; jméno serveru v tomto konkrétním případě slouží pouze k uspokojení povolené syntaxe. Stejně tak je u podřízeného klienta ignorována většina dalších nastavení, týkajících se síťového přenosu.
Pro praktické použití je možné celý proces zautomatizovat přidáním následujících direktiv do konfiguračního souboru klienta:
ControlMaster auto ControlPath ~/.ssh/controlsock-%r-%h-%p
V tomto případě je jméno řídicího soketu doplněno o jméno vzdáleného uživatele, adresu a port vzdáleného serveru. SSH klient po spuštění nejprve zkontroluje, zda existuje řídicí soket. Pokud ne, začne se chovat jako master a vytvoří jej. Další SSH klient spuštěný se stejnými parametry již řídicí soket najde a zachová se jako slave.
Teď, když nám sdílené spojení funguje, je na čase se zamyslet, k čemu vlastně může být dobré ☺. Jedna z výhod sdílení spojení je rychlost. Díky absenci navazování síťového spojení a autentizace je doba do otevření terminálu kratší přibližně sedminásobně. Na mém počítači jsem dospěl k následujícím číslům:
$ # Sdílené spojení $ time ssh server.example.com exit real 0m0.083s user 0m0.005s sys 0m0.005s $ # Bez sdílení $ time ssh server.example.com -S none exit real 0m0.551s user 0m0.015s sys 0m0.005s
Za určitých okolností může být výhodou i absence autentizace, zvláště pokud je řešena nějakým náročným způsobem (jednorázové/složité heslo, port knocking, atd.). Nevýhodou na druhé straně může být zneužitelnost sdíleného soketu místním superuživatelem, neměli bychom tedy tuto vlastnost zapínat na počítači, kde superuživateli plně nedůvěřujeme. Další nevýhodou může být to, že master relace se po odhlášení zablokuje a čeká, dokud neskončí všechny slave relace. Z toho důvodu je lepší řídicí relaci ukončovat interaktivním příkazem (Enter) ~&, který řídicí SSH proces přenese na pozadí, kde počká, dokud bude jeho služeb zapotřebí.
Závěr
Tímto dílem končí seriál o zajímavých vlastnostech balíku OpenSSH. Nebylo mým cílem vše popsat do největší podrobnosti, místo toho jsem se snažil ukázat na některé více či méně známé techniky a postupy. Děkuji všem čtenářům za podnětné komentáře pod jednotlivými články a těším se na další setkání u dalších článků.