SSH tunneling

Šifrovaný tunel skrz nezabezpečenou síť

Petr Koloros

Co se dozvíte v této přednášce:
Co je to SSH a jak funguje:

SSH znamená Secure SHell a slouží k připojení na vzdálený počítač unixového typu, který danou službu podporuje. Na druhé straně musí být odpovídající démon, který poslouchá na nějakém portu, klasicky 22. Jinak je to velmi podobné klasickému telnetu, který jistě všichni znáte a který je naprosto nezabezpečený. Kromě bezpečnosti nabízí SSH navíc takzvané forwardování portů, čili prostředek, který lze vytvořit zabezpečený tunel.

Vraťme se ale zpět k SSH a vysvětleme si, jak funguje. Existuje víc druhů klientů a my se zaměříme na OpenSSH, který je asi nejpoužívanější. Kolegům s operačním systémem Microsoft Windows doporučím podívat se do menu od jejich klienta. Identický postup, jako ten, co tu budu popisovat, by tam měl být intuitivní a zřejmý. Pro bližší informace doporučuji tento odkaz: http://the.earth.li/~sgtatham/putty/0.53b/htmldoc/Chapter8.html

Jak tedy SSH funguje? Je to prosté.

Chcete se přihlásit na nějaký server. Zadáte tedy příkaz

ssh user@stroj

a vyskočí na vás požadavek na zadání hesla, stejného jako kdybyste se přihlašovali fyzicky u tohoto stroje a po jeho úspěšném zadání dostanete příkazovou řádku, úplně stejně, jako kdyby jste to provedli nikoliv na dálku, ale lokálně.

Toto byl tedy klasický případ. Ovšem stroje, na které jste se ještě nehlásili, na vás vybafnout čímsi, co se nazývá "fingerprint", čili otisk prstu. Děje se tak proto, že váš počítač ještě nezná veřejný klíč vzdáleného počítače a proto vám nabídne alespoň fingerprint, abyste si ověřili, zda se hlásíte opravdu na správný stroj.

Příklad:

The authenticity of host 'pocitac (xxx.xxx.xxx.xxx)' can't be established.
RSA key fingerprint is 06:bf:46:8e:b0:1b:65:0e:9e:a2:bc:10:c9:64:ca:7c.
Are you sure you want to continue connecting (yes/no)?

Pokud otisku, který vám nabízí, moc nevěříte, můžete to vzdát (Ctrl-C), nebo to risknete, přidáte si tento fingerprint do své databáze (zmáčknutím klávesy 'y'):

Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'pocitac' (RSA) to the list of known hosts.

a pak se honem poběžíte podívat do adresáře

/etc/ssh/

kde si toto pomocí příkazu

ls *.pub | xargs -n 1 ssh-keygen -l -f

ověříte. Pokud mezi vypsanými fingerprinty najdete ten, který vám to při spojení nabízelo, tak je to v pořádku. Pokud ne, tak jste nejspíše byly po cestě přesměrování přes nějakého záškodníka a je třeba to nějak řešit.

V praxi existují dva způsoby, jak se autentizovat na server. Nyní si je popíšeme:

Způsob první - autentizace heslem účtu

Předpokládejme, že klientský počítač již zná veřejný klíč serveru, na který se hlásí. Při navazování kontaktu se zeptá tohoto serveru a pokud jeho veřejný klíč souhlasí s tím, co má klient ve své databázi veřejných klíčů, nebude nás již otravovat s fingerprintem, ale rovnou započne další fázi. Zkusí se serveru zeptat, jestli zná klientský veřejný klíč. Pokud nikoliv, autentizace proběhne klasickou metodou pomocí standardního jména a hesla, které bude ssh klient vyžadovat z konzole a cílový počítač tedy dostává informace, jako kdybyste u toho serveru seděli. Jméno a heslo je pochopitelně kódované a to 256 bitovým klíčem, který je speciálně vygenerován pro toto sezení a bude se jím šifrovat veškerá následující komunikace. Tento klíč je poslán hned po autentizaci metodou RSA nebo DSA. Pro vlastní šifrování se pak používá taková šifra, na které se dohodl klient po prohlédnutí nabídky serveru. Mezi nejběžnější patří 3DES, ArcFour, DES a AES (ve verzi protokolu SSH2). Tyto klíče jsou již symetrické na rozdíl od prvotní autentizace.

Způsob druhý - autentizace klíčem

Pokud nakopírujeme náš veřejný klíč do souboru authorized_keys, například takto:

user@server:~$ cp client_public_key >> .ssh/authorized_keys

Poznámka: při použití klíčů SSH protokolu verze 2 se používá soubor authorized_keys2

probíhá autentizace následovně. Klient řekne serveru, který veřejný klíč si přeje použít a server jej vybere z výše uvedeného souboru a zakóduje jím nějaký náhodný blok dat, který pošle klientovi. Ten jediný má soukromý klíč, který odpovídá použitému veřejnému klíči a tudíž tento blok dat rozkóduje a pošle zpět serveru, který jej porovná a pokud to souhlasí, tak je uživatel úspěšně autentizován a komunikace začne vesele probíhat za pomocí nějaké z dostupných šifer pro vlastní komunikaci (viz výše).

Druhá metoda má několik výhod a nevýhod. Můžeme si náš veřejný klíč poslat na více serverů a tedy se hlásit na více míst bez hesla, nebo s heslem (passphrase), které je nutno zadat při používání soukromého klíče při dekódování prvotního náhodného bloku dat pro server (viz dále). Nepřenášíme tedy sítí naše uživatelské heslo, ale vše se odehrává na úrovni klíčů. Nevýhoda této metody je ta, že pokud se někdo dostane k našemu soukromému klíči, je mu cesta otevřená a proto je možnost ním jej jen tak hala-bala na nějakém počítači, nýbrž zašifrovaný heslem (passphrase). Pak tedy při každém použití tohoto soukromého klíče musíme zadat heslo a i kdyby nám ho někdo odcizil, je mu k ničemu.

Jak a kam generovat klíč?

Co musíme udělat po instalaci klienta na svůj počítač? Vygenerovat si příslušný klíč, pokud ještě nebyl vygenerován, nebo zkopírován odjinud. Těchto klíčů je několik. Jednak klíč pro váš počítač a jednak pro vás, jako uživatele. Klíče se generují takto:

silk@701-2:~/.ssh$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/silk/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/silk/.ssh/id_dsa.
Your public key has been saved in /home/silk/.ssh/id_dsa.pub.
The key fingerprint is:
be:fd:c8:ae:c6:80:19:cc:2f:85:e2:b5:84:40:02:03 silk@701-2

Jak je vidět, vygenerovali jsme klíč typu DSA. Máme na výběr ještě metodu RSA, která se užívá především v SSH protokolu verze 1. ssh-keygen nám takto vygeneruje pár veřejný/privátní klíč, který pak používáme během spojení. Máme také na výběr, jestli si náš veřejný klíč necháme zašifrovat, nebo nikoliv. To nám určuje, zda bude při použití tohoto klíče bude nutno toto heslo zadávat. Pokud zvolíme prázdné heslo a použijeme metodu s kopírováním našeho veřejného klíče na vzdálené servery, nebudeme muset zadávat vůbec nic. Jenom příkaz k přihlášení. Toto ovšem není zrovna moc bezpečné a proto je lepší při této metodě přeci jenom nějaké heslo zvolit. Abychom ale toto heslo nemuseli zadávat pokaždé znovu, můžeme použít program ssh-agent, který si heslo zapamatuje po dobu svého běhu.

Klíče jsou běžně uloženy ve vašem domovském adresáři na této cestě:

~/.ssh

a mají různé názvy, jak uvádí tato tabulka:

SSH protokolGenerováníJména klíčů
1ssh-keygen -t rsa1identity, identity.pub
2ssh-keygen -t rsaid_rsa, id_rsa.pub
2ssh-keygen -t dsaid_dsa, id_dsa.pub

Klíče pro váš počítač (nikoliv pro vás, jako uživatele), najdete většinou v adresáři /etc/ssh. Nyní tedy znáte asi vše potřebné k používání SSH.

Jak fungují tunely

Jak již bylo řečeno, SSH používá zabezpečený kanál pro komunikaci. A tento kanál lze použít též pro přenos jiných dat. V našem případě budeme hovořit tedy o SSH tunelování a to sice komunikace mezi jednotlivými porty dvou počítačů. nejlépe bude uvádět rovnou příklady:

Příklad vybírání pošty přes POP3 zabezpečeně:

ssh -L 1110:mailserver.nekde.cz:110 mailserver.nekde.cz

A co že jsme to vlastně udělali? Při čtení pošty se běžně hlásíme na nějaký server (třeba mailserver.nekde.cz) a port 110. V našem případě jsme si tento port z daného mailserveru zpřístupnili na našem lokálním počítači pod portem 1110. Takže teď si můžeme mailového klienta vyplnit údaji:

 Server pro poštuPort
Dřívemailserver.nekde.cz110
Nynílocalhost1110

A co že znamenaly ony parametry, které jsme při spojení použili? Význam je následující:

-L localport:remoteaddr:remoteport - zavedení mapování vzdáleného portu na vzdáleném stroji na námi zvolený lokální port

Stejně tak můžeme použít i opačné mapování (tj zpřístupnění lokálního portu na zvolený port vzdáleného stroje):

-R remoteport:localmachine:localport

Takže otevřeme port na vzdáleném stroji, kterýžto bude přesměrováván na náš počítač a zadaný lokální port. Nejlépe to uvedeme na příkladu:

ssh -R 8000:localhost:80 user@firewall

Zde jsme zpřístupnili náš webový server (běží na portu 80) všem lidem na firewalu a portu 8000. Toto je velmi výhodné, pokud jsme například za NATem, kdy sice můžeme zevnitř navazovat spojení ven, ale nikdo ho nemůže navázat k nám dovnitř. Pokud použijeme zmíněný postup, port na firewallu bude vidět a bude předáván přes SSH tunel na náš počítač. Pak bude každému umožněno vidět obsah našich webových stránek i když jsme za NATem.

Nyní tedy umíme udělat jednoduchý tunel. Co když se to ale nevede? Jak si ověříme, jestli se tunel povedl?

Ověření existence tunelu

Na lokální straně to můžeme ověřit příkazem:

netstat -l --tcp

který nám vypíše všechny lokální porty, které jsou otevřené. Měli bychom tam vidět lokální port, který jsme zvolili při zavádění tunelu. Na vzdálené straně to zjistíme identickým příkazem, nebo se tam můžeme kouknout vzdáleně telnetem:

telnet remotehost port

Kde zadáme vzdálený port, použitý ve vytváření tunelu. Je pochopitelné, že jsme tunel vytvářeli pro zpřístupnění nějakého existujícího portu na vzdálené či lokální straně, takže tato metoda slouží jak k ověření vzdáleně vytvořeného portu, tak i existujícího.

Potřebujeme mít možnost zadávat příkazy na vzdálené straně?

Pokud vytváříme tunel, tak běžně asi nikoliv. A proto musíme nějak ošetřit běžné přihlášení, které nám kromě tunelu také vrátí příkazovou řádku na vzdáleném stroji a můžeme vesele zadávat příkazy, nebo si splést konzoli a provést nějakou neplechu, protože jsme si mysleli, že jsme na lokálním počítači.

K zablokování možnosti zadávat příkazy použijeme přepínače:

ssh -N -f -L ...

Přičemž -L nám již dělá vlastní tunel. Po zadání tohoto příkazu běží ssh na pozadí a dostanete zpět svojí příkazovou řádku na lokálním počítači. Má to jednu nevýhodu a to sice zrušení tohoto tunelu. Nezbude nám asi nic jiného, než použít příkaz kill s příslušným číslem procesu.

Pokud si ale necháme k dispozici příkazovou řádku i na vzdáleném konci, SSH nám nabízí zobrazování různých informací. Seznam těchto možností si zobrazíme zmáčknutím ~? na vzdálené straně (tj v té příkazové řádce, která nám byla přidělena při tvorbě ssh tunelu). Pak uvidíme seznam podobný tomuto:

Supported escape sequences:
~. - terminate connection
~B - send a BREAK to the remote system
~C - open a command line
~R - Request rekey (SSH protocol 2 only)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

Takže například zadáním ~. ukončíme tunel, ~# si zobrazíme vytvořené tunely a podobně.

Více portů != více tunelů

Mohlo by se zdát, že budeme potřebovat více tunelů, pokud chceme tunelovat více portů. Tak tomu není, protože to můžeme zařídit jedním příkazem. Pro ukázku si rozšíříme náš příklad s tunelováním POP3 protokolu při stahování pošty též o SMTP protokol, pro její odesílání. Potřebujeme tedy tunelovat dva porty. A jak to provedeme? Jednoduše:

ssh -L 1110:mail.neco.cz:110 -L 1025:mail.neco.cz:25 user@server

A nyní máme vytvořený jeden tunel, který nám přenáší komunikaci mezi více porty. Po příslušném nastavení změněných adres tedy můžeme odesílat i přijímat poštu s klidným vědomím, že si ji nebude číst někdo nepovolaný.

A jak se tuneluje v Putty?

Pro vysvětlení základních principů bylo řečeno dost a proto opakování téhož v jiném kabátě nepovažuji za přínosné. Navíc existuje pěkná stránka, kde si to můžete přečíst: http://people.ece.cornell.edu/schuh/tunnelssh

Tunely pro grafické aplikace - X forwarding

V operačních systémech unixového typu jsou grafické aplikace provozovány pomocí X serveru. Tento dokáže obsluhovat aplikace i na dálku a proto pro nás není problém si nějakou takovou aplikaci z docela jiného stroje. Běžně bychom to udělali tak, že bychom se tam přihlásili a pustili si aplikaci. Abychom viděli grafický výstup z onoho programu, musí mezi sebou komunikovat oba X servery, vzdálený s lokálním. Ty ale neví zhola nic o našem propojení a proto jen tak fungovat nebudou. Budeme toho muset docílit pomocí dodatečného nastavení.

X forwarding - nezabezpečeně:

Máme tedy nějaké to přihlášení a nyní je třeba systému sdělit, odkud a kam má přenášet informace o zobrazení grafických dat. Musíme tedy provést dvě věci:

  1. Na vzdálené straně nastavit proměnou DISPLAY tak, aby byl výstup zobrazen na blízkém konci. Příklad:

    export DISPLAY=blizky.konec.cz:0

  2. Na blízkém konci je ale třeba nastavit přijímání těchto dat, což provedeme příkazem:

    xhost +vzdaleny.konec.cz

.. a tím máme vše nastaveno. Kromě vlastního propojení se nám vytvoří další kanál z cílového stroje na lokální stroj a to konkrétně na port 6000, což je port, na kterém X server standardně poslouchá. Můžeme si to ověřit například příkazem netstat:

silk@silk:~$ netstat --tcp
Aktivní Internetová spojení (w/o servery)
Proto Přích-F Odch-F Místní Adresa Vzdálená Adresa Stav
tcp 0 0 silk.sh.cvut.cz:6000 pocitac.nekde.cz:1934 SPOJENO
tcp 0 0 silk.sh.cvut.cz:59911 pocitac.nekde.cz:slogin SPOJENO

Vše tedy bude fungovat skvěle až na fakt, že komunikace mezi jednotlivými X servery bude totálně nezabezpečená. Jak to tedy vyřešit, aby to bylo bezpečné? K tomu nám SSH nabízí své prostředky:

X forwarding - bezpečně:

SSH nám nabízí dvě možnosti:

SSH -X další parametry

nebo nastavíme v souboru /etc/ssh/ssh_config (soubor s konfigurací SSH klienta), parametr:

ForwardX11 yes

V těchto případech se o tunelování komunikace mezi X servery postará samotné SSHčko. Nyní tedy vidíme, že komunikace již neotvírá speciální kanál pro X servery, ale vše je tlačeno přes naše SSH připojení:

Aktivní Internetová spojení (w/o servery)
Proto Přích-F Odch-F Místní Adresa Vzdálená Adresa Stav
tcp 0 0 silk.sh.cvut.cz:59938 pocitac.nekde.cz:slogin SPOJENO

Okénka máme stejná, jako v prvním případě a již se nemusíme bát, že by nám chtěl někdo naší Xkovou relaci odposlechnout.

Výhody a nevýhody používání SSH Tunelů

Výhody:

Nevýhody: