Klíče v SSH
Co se dozvíte v článku
Přihlašování pomocí páru klíčů zvyšuje výrazně bezpečnost SSH. Případný útočník nemá možnost hádat kombinaci jména a hesla, pro uživatele je navíc vše pohodlnější. Nemusí si nikam ukládat unikátní složité heslo pro každou službu a pak ho vyhledávat v případě potřeby přihlášení.
Místo toho si vytvoří pár klíčů: veřejný a soukromý. Veřejný klíč nahraje na všechny servery, ke kterým se chce v budoucnu přihlašovat. Soukromý klíč zůstává v souboru na lokálním disku a nesmí jej nikdy opustit.
Při pokusu o přihlášení pak SSH klient pošle serveru žádost podepsanou tímto soukromým klíčem. Server při přijetí tohoto požadavku zkontroluje podpis na základě dříve nahraného veřejného klíče. Pokud je tento klíč uveden v seznamu autorizovaných klíčů pro daného uživatele, dojde k přihlášení.
Klíč na disku
Bezpečnostní riziko tu představuje především soukromý klíč uložený v běžném souboru na disku. Ten je chráněn pomocí šifrování a odemyká se do paměti, aby mohl být použit. Pro zjednodušení života správců byl vynalezen SSH agent, který si klíče drží v paměti a nevydá je žádnému neprivilegovanému procesu. Nabízí ale rozhraní pro jeho použití.
Dešifrovaný klíč je tak připraven k použití a pokud se chce uživatel někam přihlásit, jeho SSH klient se připojí k agentovi a vyžádá si podpis přihlašovací zprávy. Agent může být nastaven tak, že každý požadavek musí být uživatelem potvrzen, aby si libovolný proces nemohl potichu vystavovat libovolný počet podpisů.
Přesto všechno stále existuje teoretická možnost odcizení soukromého klíče. Ať už z paměti počítače, kde ji má uloženou agent, nebo třeba z disku, kde může být klíč chráněn slabým (nebo dokonce žádným) heslem. Existuje ale možnost, jak celý proces zajišťovaný agentem přesunout na hardwarový token a tím naprosto oddělit soukromý klíč od zbytku systému.
U2F jako úložiště klíčů
U2F je standard konsorcia FIDO, který nabízí bezpečné dvoufaktorové přihlášení, typicky k webovým službám. Základem je hardwarové zařízení – token. To se vkládá do USB nebo je možné jej u některých modelů připojit k mobilnímu telefonu pomocí NFC. Takový token stojí obvykle vyšší stokoruny a lze jej pořídit u různých výrobců, stačí hledat U2F.
Uvnitř tokenu je od výroby napevno vestavěn soukromý klíč, který zařízení nikdy nevydá. Je to tajemství, které nikdy neuvidí ani uživatel, ani nikdo jiný. Každý token je pak unikátní a pomocí algoritmů pracujících s veřejným klíčem pak jen prokazuje svou fyzickou existenci. Pokud uživatel takto dokáže, že drží v ruce správný token, může být přihlášen.
Každá služba, která nabízí přihlašování pomocí U2F, při registraci nového tokenu vytvoří náhodnou výzvu (nonce), kterou si uloží do uživatelské databáze. Zároveň ji pošle uživateli, jehož software jej předá do tokenu. Uvnitř se výzva pomocí funkce HMAC-SHA256 spojí s vestavěným soukromým klíčem a vzniká nový soukromý klíč, který je unikátní pro danou webovou službu.
Na základě této operace je pak odvozen veřejný klíč, který se předá zpět serveru. Výhodou je, že token nemusí mít žádnou persistentní paměť pro ukládání párů klíčů. Ty vznikají a zanikají podle zaslané výzvy. Dokud je výzva od jedné služby stejná, je i stejný pár klíčů v tokenu a může proběhnout potvrzování identity.
Přihlášení pomocí U2F
Pokud se má uživatel někdy v budoucnu pomocí svého tokenu přihlásit, služba vygeneruje další výzvu (challgenge), tentokrát jednorázovou. Obě výzvy jsou pak předány do prohlížeče a poté po USB nebo NFC do tokenu. Opět je vygenerován náš známý pár klíčů a soukromý klíč je použit k podepsání jednorázové výzvy. Obvykle je to ještě doprovázeno nutností stisknout fyzické tlačítko na tokenu, čímž uživatel potvrdí, že je si vědom probíhajícího přihlašovacího procesu.
Tato podepsaná zpráva se pak vrací serveru, který ji ověří pomocí veřejného klíče, který zná od registrace zařízení. Pokud je všechno v pořádku, uživatel dokázal, že má stále v držení stejný token a tím prokázal svou identitu. Je bezpečně přihlášen.
Pravděpodobně jste tu zaznamenali podobnost obou procesů. U2F vlastně využívá velmi podobných mechanismů, jaké známe z SSH. Jen místo pevného páru klíčů zapojuje token a generuje si páry klíčů ad-hoc podle zaslané výzvy. Pokud tohle všechno zkombinujeme, můžeme se bezpečně přihlašovat i na SSH.
U2F v SSH
V únoru vyšla nová verze OpenSSH 8.2, která v sobě podporu U2F zahrnuje. To umožňuje výše zmíněný proces využít právě pro SSH. Stačí mít dostatečně aktuální verzi OpenSSH a v držení nějaký ten U2F token.
OpenSSH zavádí dva nové typy SSH klíčů: ecdsa-sk
a ed25519-sk
. Možnost jejich použití závisí na schopnostech konkrétního tokenu. Součástí standardu je povinnost implementovat ECDSA, tu tedy umí všechny tokeny. Pokud chcete používat ED25519, musíte hardware obezřetněji vybírat.
Poznámka: V případě YubiKey například potřebujete token s podporou FIDO2, tedy firmware minimálně verze 5.2.3. Nižší verze podporují jen ECDSA.
Já jsem zkoušel podporu na distribuci Debian, která nabízí balíčky s novějším OpenSSH ve větvi testing a unstable. Je tedy potřeba si do /etc/apt/sources.list
přidat patřičný řádek a poté při instalaci balíčku použít parametr -t
pro výběr jiné než standardní větve. Více viz článek o míchání větví v Debianu.
Pro vytvoření páru klíčů použijeme standardní utilitu ssh-keygen
, kterou jen požádáme o nový typ klíče. Vzniknou nám tradičně dva soubory, které obvykle obsahují veřejný a soukromý klíč. V tomto případě ale samozřejmě skutečný soukromý klíč nezískáme, ten je uvnitř tokenu. V druhém souboru (soukromém) je uložena výzva, která byla použita pro sestavení klíčů a získání toho veřejného.
$ ssh-keygen -t ecdsa-sk -C "Popis klice"
Při generování nás nástroj vyzve ke stisku tlačítka na tokenu, v případě YubiKey se dotykové tlačítko rozbliká a čeká na naši akci. Jakmile se ho dotkneme, generování proběhne a uloží se nám dva zmíněné soubory.
Identifikace uživatele (výzva) je v souboru /home/$USER/.ssh/id_ecdsa_sk
a vytvořený veřejný klíč pak najdeme v /home/$USER/.ssh/id_ecdsa_sk.pub
. První z nich slouží k opětovnému sestavení soukromého klíče uvnitř tokenu, druhý pak k ověření podpisu při pokusu o přihlášení.
Přihlášení na server
Teď zbývá jen klasicky nahrát veřejný klíč na server do /home/$USER/.ssh/authorized_keys
. Na začátku řádku je uveden typ klíče, v našem případě bude vypadat nějak takto:
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrL…
Server musí tyto klíče podporovat, musí mít tedy OpenSSH také alespoň ve verzi 8.2. Zajímavá je pak možnost omezit používané klíče jen na ty generované pomocí U2F. Pokud máte v konfiguraci vyjmenované některé jiné metody, nezapomeňte mezi ně přidat i ty nové, jinak je server odmítne a nepřihlásíte se.
cat /etc/ssh/sshd_config … PubkeyAcceptedKeyTypes sk-ecdsa-sha2-nistp256@openssh.com,sk-ssh-ed25519@openssh.com …
Nyní se stačí běžným způsobem přihlásit pomocí SSH klienta. Ten nás opět vyzve k potvrzení přihlášení stiskem tlačítka na tokenu a je hotovo. Výhodou samozřejmě je, že nám soukromý klíč nikdo nemůže ukrást a my můžeme stejný mechanismus používat na všech SSH serverech, ale i na dalších webových službách.
Záloha klíčů
Nabízí se samozřejmě otázka, jak postupovat při ztrátě našeho tokenu. Záloha samotného klíče pochopitelně není možná, nedokážeme ho z tokenu dostat. Obvyklým řešením je pořídit si rovnou tokenů více, provést stejnou operaci pro každý z nich a na servery nahrát (pokud možno automatizovaně) všechny takto získané veřejné klíče. Záložní token můžeme mít bezpečně uložený a použijeme ho jen v případě nouze pro výměnu veřejných klíčů po pořízení nového tokenu.
Druhou variantou je kombinace s klasickým párem klíčů uloženým na disku. Ten můžeme předem vygenerovat na bezpečném počítači, soukromý klíč uložit v trezoru (třeba v podobě QR kódu) a na servery opět distribuovat záložní veřejný klíč.
Výhodou generování klíčů v U2F je, že útočníkovi nestačí ukrást vám samotný token. K úspěšném přihlášení by totiž ještě potřeboval soubor s výzvou, který je bezpečně uložen na vašem počítači, ideálně na šifrovaném disku. Stále je tedy zachován princip druhého faktoru.