Hlavní navigace

Sdílené, interaktivní a hashované OpenSSH

12. 7. 2011
Doba čtení: 6 minut

Sdílet

Seriál o zajímavých vlastnostech OpenSSH se chýlí ke konci. Dnes se podíváme, jak zabezpečit seznam známých serverů před únikem dat a jak s SSH přenést proměnné prostředí. Dozvíme se také, že SSH klienta je možné ovládat i interaktivně. Na závěr zjistíme, jak po jednom SSH spojení sdílet více terminálových relací.

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:

root_podpora

$ # 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ů.

Byl pro vás článek přínosný?

Autor článku

Ondřej Caletka vystudoval obor Telekomunikační technika na ČVUT a dnes pracuje ve vzdělávacím oddělení RIPE NCC, mezinárodní asociaci koordinující internetové sítě.