Skip to content
Martin Skalicky edited this page Aug 5, 2026 · 1 revision

SSH do hloubky

SSH je nejpoužívanější kryptografický protokol, který kdy budeš obsluhovat ručně. Zároveň je to jediná cesta na tvůj server, takže se vyplatí vědět, co se při připojení doopravdy děje — ne proto, aby to fungovalo, ale proto, abys věděl, co znamená, když to nefunguje nebo když se něco změní.

Základní zabezpečení je na zabezpečení serveru. Tahle stránka jde hlouběji: protokol, ověřování, certifikáty, tunely a věci, které dělá málokdo a měl by.

Předpokládá veřejný a soukromý klíč a Diffie-Hellmana.

Co SSH doopravdy je

Není to „vzdálený terminál". Terminál je jen jedno z použití. SSH je šifrovaný multiplexovaný transport, do kterého se dá zabalit cokoliv:

  • interaktivní shell
  • jednorázový příkaz
  • přenos souborů (SFTP, rsync, scp)
  • přesměrované TCP porty oběma směry
  • SOCKS proxy
  • unixové sokety (třeba docker.sock)
  • pomocné kanály — přeposlaný agent, X11

Všechno tohle jede jedním TCP spojením a rozlišuje se to čísly kanálů. Proto můžeš v jednom sezení mít shell a zároveň tunel na databázi.

Protokol je popsaný v RFC 4251 až 4254 z roku 2006 a od té doby se změnily hlavně algoritmy, ne struktura.

Tři vrstvy

Vrstva Co dělá
Transportní výměna klíčů, ověření serveru, šifrování, integrita, komprese
Ověření uživatele dokazuje, kdo jsi — klíčem, heslem, tokenem
Spojová kanály, tunely, shell, přenos souborů

Pořadí je podstatné: server se ověřuje první. Než pošleš jediný znak hesla, musíš už vědět, s kým mluvíš. Kdyby to bylo obráceně, útočník uprostřed by hesla sbíral bez námahy.

Průběh připojení

sequenceDiagram
    participant K as Klient
    participant S as Server
    Note over K,S: TCP spojení na port 22
    K->>S: SSH-2.0-OpenSSH_9.6
    S->>K: SSH-2.0-OpenSSH_9.6
    Note over K,S: nešifrovaně, oba znají verzi protistrany
    K->>S: KEXINIT — seznam algoritmů, které umím
    S->>K: KEXINIT — seznam algoritmů, které umím
    Note over K,S: z průniku se vybere první shoda podle pořadí klienta
    K->>S: veřejná část dočasného klíče
    S->>K: veřejná část + host key + podpis
    K->>K: ověří host key proti known_hosts
    K->>K: ověří podpis exchange hashe
    Note over K,S: NEWKEYS — dál je vše šifrované
    K->>S: chci se přihlásit jako martin, metodou publickey
    S->>K: dobře, zkus to
    K->>S: podpis session ID svým soukromým klíčem
    S->>K: SUCCESS
    Note over K,S: otevírají se kanály — shell, tunely
Loading

Pozdrav

První dva řádky jdou otevřeně a jsou to jediná data, která si kdokoliv po cestě přečte:

nc server 22
# SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5

Odtud pochází návod „skryj verzi SSH". Nemá to smysl — verze je nutná pro obcházení historických chyb v protokolu a útočník tvou verzi stejně pozná podle nabídnutých algoritmů. Naopak: ten řetězec se započítává do podpisu, takže ho po cestě nikdo nemůže změnit, aniž by spojení selhalo.

Vyjednání algoritmů

Obě strany pošlou seznamy toho, co umí, pro každou kategorii zvlášť: výměna klíčů, host key, šifra pro každý směr, MAC, komprese. Vybere se první položka klientova seznamu, kterou umí i server. Pořadí na straně klienta tedy rozhoduje.

Co umí tvůj klient:

ssh -Q kex        # výměna klíčů
ssh -Q key        # typy host keys a klíčů uživatele
ssh -Q cipher     # šifry
ssh -Q mac        # ověřování integrity

Co nabízí konkrétní server:

nmap --script ssh2-enum-algos -p 22 server
ssh-audit server          # čitelnější, s hodnocením; pip install ssh-audit

Výměna klíčů

Proběhne Diffie-Hellman, dnes typicky na křivce X25519 v hybridu s postkvantovým mechanismem.

ssh -vv server 2>&1 | grep -iE "kex:|cipher:"
# kex: algorithm: mlkem768x25519-sha256
# kex: host key algorithm: ssh-ed25519
# kex: server->client cipher: chacha20-poly1305@openssh.com

Historie výchozích voleb v OpenSSH, ať víš, čemu odpovídá tvoje verze:

Verze Výchozí výměna klíčů
6.5 (2014) curve25519-sha256
9.0 (2022) sntrup761x25519-sha512 — první postkvantová
10.0 (2025) mlkem768x25519-sha256 — standardizovaná postkvantová

Vedlejším produktem výměny je exchange hash — otisk úplně všeho, co dosud proběhlo: obou pozdravů, obou seznamů algoritmů, host keye a veřejných částí. První takový hash se stane session ID a platí po celé spojení.

Server ho podepíše svým host keyem a tím se ověří. Kdo host key nemá, nemůže se za server vydávat — může leda přeposílat pakety, ale pak podpis neodpovídá jeho vlastní výměně.

Tohle je zároveň důvod, proč SSH nepotřebuje certifikáty: důvěru neseš ty ve svém known_hosts.

Šifrování provozu

Po NEWKEYS je vše šifrované. Z výsledku výměny se odvodí šest klíčů: pro každý směr šifrovací klíč, počáteční vektor a klíč pro integritu.

Moderní volba je AEAD šifra, kde se integrita řeší uvnitř:

  • chacha20-poly1305@openssh.com — výchozí, rychlá i bez hardwarové akcelerace
  • aes256-gcm@openssh.com, aes128-gcm@openssh.com

Kde AEAD není, používá se encrypt-then-MAC (hmac-sha2-256-etm@openssh.com). Varianty bez -etm počítají MAC z otevřeného textu a jsou horší; CBC režimy nepoužívej vůbec.

Host keys a known_hosts

Nejzajímavější část SSH, protože tady se řeší důvěra bez jakékoliv autority.

Server má vlastní dvojici klíčů, obvykle několik podle typu:

ls -1 /etc/ssh/ssh_host_*
# ssh_host_ecdsa_key       ssh_host_ecdsa_key.pub
# ssh_host_ed25519_key     ssh_host_ed25519_key.pub
# ssh_host_rsa_key         ssh_host_rsa_key.pub

First use a known_hosts

Při prvním připojení klient klíč nezná:

The authenticity of host 'server (192.168.1.10)' can't be established.
ED25519 key fingerprint is SHA256:5N3YbQm...
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Tomu se říká trust on first use. Buď je to server, nebo je to útočník — protokol to nerozliší a rozhodnutí přenáší na tebe. Když odpovíš yes, klíč se uloží do ~/.ssh/known_hosts a od té chvíle se každé připojení kontroluje.

Skoro nikdo to neověřuje a je to největší reálná mezera v běžném používání SSH.

Jak to udělat pořádně, seřazeno od nejlepšího:

1. Certifikáty. Podepiš host keys vlastní CA a klient je přijme bez ptaní. Řeší to i výměnu klíčů při reinstalaci. Viz níže.

2. Otisk z jiného kanálu. Přečti si ho na konzoli serveru přes web poskytovatele, z výstupu cloud-initu nebo z hypervizoru:

# na serveru, přes konzoli
for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done

3. SSHFP v DNS. Otisk klíče jako DNS záznam:

ssh-keygen -r server.example.cz          # vygeneruje záznamy k vložení do zóny
ssh -o VerifyHostKeyDNS=yes server.example.cz

Užitečné, ale skutečnou bezpečnost dává jen s DNSSEC — jinak jsi jen přesunul důvěru z první odpovědi SSH na první odpověď DNS.

4. Rozdat known_hosts centrálně. Ansible, /etc/ssh/ssh_known_hosts, správa konfigurací.

Co není ověření: ssh-keyscan server >> ~/.ssh/known_hosts. Tenhle příkaz se ptá po síti, tedy přesně toho, komu nevěříš. Je to zápis „důvěřuji tomu, kdo mi zrovna odpověděl". Použitelné jen tam, kde nemáš co ztratit.

Hashované known_hosts

Debian a Ubuntu mají ve výchozím stavu HashKnownHosts yes, takže v souboru nejsou jména strojů, ale jejich otisky. Chrání to seznam tvých serverů, kdyby ti někdo prohledal notebook.

Nedá se v tom pak hledat očima, ale nástroje ano:

ssh-keygen -F server                  # najdi záznam
ssh-keygen -R server                  # smaž záznam
ssh-keygen -H -f ~/.ssh/known_hosts   # zahashuj existující soubor

Když se otisk změní

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @

Neodstraňuj to reflexivně. Legitimní důvody jsou reinstalace, obnova ze zálohy nebo výměna stroje. Nelegitimní důvod je útočník uprostřed. Rozdíl poznáš jen tak, že se zeptáš, jestli se se serverem něco dělo — a pokud ne, tak dokud to nevysvětlíš, se nepřipojuj.

Když je změna očekávaná:

ssh-keygen -R server
ssh server        # a otisk zkontroluj proti konzoli

Automatická rotace

Od OpenSSH 8.5 je ve výchozím stavu UpdateHostKeys yes. Server po přihlášení pošle všechny své host keys a klient si je uloží. Umožňuje to bezbolestný přechod z RSA na Ed25519 nebo výměnu klíče bez varování u všech uživatelů.

Funguje to jen po úspěšném ověření, takže to nic neoslabuje.

Ověření uživatele

Klíčem

To, co se ve skutečnosti děje, je zajímavější než „server má můj veřejný klíč".

  1. Klient ohlásí, kterým veřejným klíčem se chce prokázat.
  2. Server se podívá do ~/.ssh/authorized_keys, jestli tam je. Pokud ne, odmítne rovnou.
  3. Klient podepíše session ID (plus jméno uživatele, služby a metody) svým soukromým klíčem.
  4. Server podpis ověří veřejným klíčem.

Klíčový detail je ten podpis nad session ID. Session ID je unikátní pro každé spojení a je do něj zapleten host key serveru. Z toho plyne:

  • Podpis nejde přehrát na jiné spojení.
  • Podpis nejde přeposlat na jiný server, protože ten má jiný host key.
  • Soukromý klíč nikdy neopustí tvůj stroj — server dostane jen podpis.

Tohle je zásadní rozdíl proti heslu. Když se přihlásíš heslem na podvržený server, útočník má tvoje heslo a přihlásí se s ním kamkoliv jinam. Když se přihlásíš klíčem, útočník má podpis, který jinde nefunguje. Klíč tedy chrání i před špatným rozhodnutím u known_hosts.

Ostatní metody

Metoda Poznámka
publickey tohle chceš
password posílá heslo dovnitř šifrovaného kanálu; vypni
keyboard-interactive dialog otázka–odpověď, tudy jde TOTP a PAM
hostbased ověřuje stroj, ne uživatele; v praxi se nepoužívá
gssapi-with-mic Kerberos, firemní prostředí

Dva faktory pořádně

Rozdíl, na kterém záleží: čárka znamená a zároveň, mezera znamená nebo.

AuthenticationMethods publickey,keyboard-interactive

Tohle vyžaduje klíč a k němu ještě kód. V PAM pak sedí pam_google_authenticator nebo Duo.

AuthenticationMethods publickey keyboard-interactive

Tohle znamená „stačí jedno z toho" a je to obvykle omyl.

Pro homelab je poctivější odpověď: hardwarový klíč s vyžadovaným dotekem je 2FA sám o sobě a je pohodlnější než opisování číslic.

Volby v authorized_keys

Málo používaná a velmi užitečná věc. Před klíč se dá napsat seznam omezení, která platí jen pro tento klíč:

restrict,from="192.168.1.0/24",command="/usr/local/bin/zaloha.sh" ssh-ed25519 AAAAC3... zaloha
Volba Co dělá
restrict zakáže všechno — tunely, agenta, X11, terminál. Základ, na kterém stavíš.
pty povolí terminál zpátky
port-forwarding, agent-forwarding povolí zpátky konkrétní věc
command="..." při přihlášení se spustí jen tohle, ať uživatel žádá cokoliv
from="1.2.3.4,10.0.0.0/8" klíč platí jen z těchto adres
permitopen="db:5432" tunel jen sem a nikam jinam
expiry-time="20271231" klíč po tomto datu přestane platit
no-touch-required u FIDO klíčů zruší nutnost doteku

command= je nejsilnější z nich. Původní příkaz uživatele najdeš v $SSH_ORIGINAL_COMMAND, takže se dá postavit rozcestník, který povolí jen konkrétní operace.

Typické použití: klíč pro zálohovací stroj, který smí spustit jen rsync v režimu čtení a odnikud jinud než z tvé sítě. Kdyby ten klíč unikl, útočník nedostane shell.

ssh-agent

Klíč chráněný heslem je bezpečný a otravný. Agent je proces, který si klíč po jednom odemknutí drží v paměti a podepisuje jím za tebe.

ssh-add -l                    # co je načtené
ssh-add ~/.ssh/id_ed25519     # přidat
ssh-add -t 4h                 # přidat na omezenou dobu
ssh-add -c ~/.ssh/id_ed25519  # ptát se na potvrzení u každého použití
ssh-add -D                    # zapomenout všechno

Do ~/.ssh/config patří:

AddKeysToAgent yes

Agent nikdy nevydá soukromý klíč. Umí jen podepsat, co mu pošleš. Kdo se dostane k jeho soketu ($SSH_AUTH_SOCK), tvůj klíč neukradne — ale může se s ním přihlašovat, dokud agent běží. Z toho plyne následující.

Přeposílání agenta je nebezpečné

ssh -A zpřístupní tvého agenta na vzdáleném stroji, abys z něj mohl skočit dál.

Kdo je na tom stroji root, může tvého agenta používat. Ne někdy, vždycky — soket je běžný soubor a root ho přečte. Dokud jsi připojený, může se tvým klíčem přihlásit kamkoliv, kam ty. A ty se to nedozvíš.

Správné řešení je ProxyJump, které tenhle problém nemá vůbec:

ssh -J brana vnitrni-server
Host vnitrni-*
    ProxyJump brana

Rozdíl: klíč se použije lokálně, brána jen přeposílá zašifrovaný provoz. Nevidí do něj a nemá k čemu přistupovat. Skládá se to i do řetězu (-J bastion1,bastion2).

Když se přeposlání agenta opravdu nedá obejít, aspoň zapni ssh-add -c, ať každé použití vyžaduje tvé potvrzení, a nikdy ho nedávej na stroj, kterému nevěříš.

SSH certifikáty

Tohle je funkce, kterou má OpenSSH od roku 2010, umí ji málokdo a řeší dva největší provozní problémy naráz.

Problém 1: máš deset serverů, každý s vlastním host keyem, a deset lidí, kteří na každý potřebují known_hosts.

Problém 2: máš authorized_keys na deseti serverech. Když někdo odejde, musíš jeho klíč odebrat na všech.

Certifikát je podepsané tvrzení o klíči — tentýž princip jako u TLS, jen mnohem jednodušší formát bez X.509 a bez řetězů.

Vytvoření CA

ssh-keygen -t ed25519 -f user_ca -C "SSH user CA"
ssh-keygen -t ed25519 -f host_ca -C "SSH host CA"

Dvě oddělené CA, ať klíč pro podpis serverů neumí vyrábět uživatele. Soukromé klíče patří mimo běžné servery.

Certifikát pro uživatele

ssh-keygen -s user_ca -I "martin@notebook" -n martin,deploy \
           -V +52w -z 1 ~/.ssh/id_ed25519.pub
# vznikne ~/.ssh/id_ed25519-cert.pub
  • -I — popisek, který se objeví v logu serveru
  • -nprincipals, tedy jako kteří uživatelé se smí přihlásit
  • -V +52w — platnost; tohle je ta hodnota, kvůli které to děláš
  • -z — sériové číslo, kvůli případnému odvolání

Na serveru stačí jediný řádek:

TrustedUserCAKeys /etc/ssh/user_ca.pub

A authorized_keys už nemusí existovat vůbec. Kdo má platný certifikát od tvé CA a správný principal, dostane se dovnitř. Odchod člověka řešíš tím, že mu příště certifikát nevystavíš — nikam se nepřihlašuješ, nic nemažeš.

Certifikát pro server

ssh-keygen -s host_ca -I "web01" -h -n web01.example.cz,192.168.1.10 \
           -V +52w /etc/ssh/ssh_host_ed25519_key.pub
# /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

U klienta stačí jeden řádek v known_hosts pro celou infrastrukturu:

@cert-authority *.example.cz ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...

A tím zmizí trust on first use. Nový server naběhne a klienti se na něj připojí bez jediné otázky, protože jeho certifikát podepsala CA, které už věří. Reinstalace serveru přestane být událost.

Kontrola a odvolání

ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub    # co v certifikátu je

# seznam odvolaných
ssh-keygen -k -f revoked.krl id_ed25519-cert.pub
# a v sshd_config:  RevokedKeys /etc/ssh/revoked.krl

V praxi ale odvolávání skoro nepotřebuješ — stačí krátká platnost. Certifikát na osm hodin se odvolávat nemusí, ráno prostě vyprší. To je stejná úvaha, kterou dělá tls internal v Caddy.

Hardwarové klíče

OpenSSH od verze 8.2 umí klíče uložené v FIDO2 tokenu:

ssh-keygen -t ed25519-sk -O resident -O verify-required -C "yubikey"
  • ed25519-sk — soukromá část zůstane v tokenu, ven se nikdy nedostane
  • -O resident — klíč jde z tokenu obnovit na novém počítači (ssh-keygen -K), takže nepotřebuješ zálohu souboru
  • -O verify-required — kromě doteku ještě PIN

Vznikne dvojice souborů, ale ten „soukromý" je jen odkaz do tokenu. Bez fyzického tokenu je k ničemu. Zkopírovaný malwarem, uniklý ze zálohy, nalezený na ztraceném notebooku — pořád k ničemu.

Praktická poznámka: pořiď si dva tokeny a oba klíče vlož do authorized_keys. Ztráta jediného tokenu jinak znamená ztrátu přístupu.

Tunely a přesměrování portů

Nejužitečnější a nejméně známá schopnost SSH. Ke všem třem variantám platí, že se nemusí zabírat terminál — -N znamená „žádný příkaz", -f pošle na pozadí.

Místní: -L

Otevři port u sebe, provoz vylez na druhé straně.

ssh -L 8080:localhost:80 server
# http://localhost:8080 u tebe = http://localhost:80 na serveru

Kanonické použití: dostat se na administraci, která poslouchá jen na 127.0.0.1 a záměrně není vystavená. To je přesně ten správný způsob, jak zpřístupnit databázi nebo panel bez reverse proxy a bez otevírání portu.

ssh -N -L 5432:db-server:5432 brana
# lokální psql se připojí na localhost:5432 a mluví s databází ve vnitřní síti

Ten prostřední údaj se rozlišuje z pohledu serverulocalhost:80 je server sám, db-server:5432 je stroj, na který server dosáhne.

Vzdálený: -R

Opačný směr. Otevři port na serveru, provoz vyleze u tebe.

ssh -R 8080:localhost:3000 server
# kdo na serveru sáhne na localhost:8080, dostane tvou aplikaci na portu 3000

Tohle je takzvaný reverzní tunel a je to plnohodnotná náhrada za port forwarding na routeru, když jsi za CGNATem. Malá VPS s veřejnou adresou stačí.

Ve výchozím stavu se port na serveru otevře jen na 127.0.0.1. Pro přístup zvenku je potřeba na serveru GatewayPorts clientspecified a u klienta uvést adresu:

ssh -R 0.0.0.0:8080:localhost:3000 server

Přidej -o ExitOnForwardFailure=yes. Bez toho se spojení naváže, i když se tunel nepovede otevřít, a ty se pak divíš, proč nic nefunguje.

Pro trvalý provoz použij autossh nebo systemd jednotku s Restart=always, ServerAliveInterval 30 a ServerAliveCountMax 3.

Dynamický: -D

SOCKS5 proxy — všechno, co do ní pošleš, vyleze na serveru.

ssh -N -D 1080 server
curl --socks5-hostname localhost:1080 http://vnitrni-server/

Nastav to v prohlížeči a máš „VPN" na jeden příkaz. Pro pohodlný trvalý přístup je WireGuard lepší, na jednorázovou potřebu je tohle rychlejší.

Použij --socks5-hostname (a v prohlížeči „proxy DNS"), jinak se jména překládají u tebe a vnitřní jména nefungují.

Multiplexování

Druhé a další připojení na tentýž stroj může použít existující spojení a naváže se okamžitě, bez handshake:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%C
    ControlPersist 10m

%C je hash celé kombinace, což řeší limit délky cesty u unixového soketu — s %r@%h:%p na to u dlouhých doménových jmen narazíš.

Kromě rychlosti to znamená jedno přihlášení místo deseti, což se hodí u hardwarového klíče s dotekem. Nevýhoda: ssh -O exit server musíš použít, když chceš spojení opravdu zavřít.

Konfigurace klienta

~/.ssh/config je nejlepší investice do pohodlí. Platí první nalezená hodnota, takže obecné Host * patří na konec souboru, ne na začátek.

Host *
    AddKeysToAgent yes
    ServerAliveInterval 30
    ServerAliveCountMax 3
    HashKnownHosts yes

Host brana
    HostName 89.24.x.x
    User martin
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_brana
    IdentitiesOnly yes

Host nas media pihole
    ProxyJump brana
    User martin

Host github.com
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

IdentitiesOnly yes je důležitější, než vypadá. Bez něj klient nabízí serveru postupně všechny klíče z agenta. Jednak tím prozradí, které klíče máš, jednak po pár pokusech narazí na MaxAuthTries a dostane Too many authentication failures — přestože ten správný klíč má.

Ověření, co se na daný stroj skutečně použije:

ssh -G nas      # výsledná konfigurace po vyhodnocení všech pravidel

Konfigurace serveru

Základ je na zabezpečení serveru. Tady to, co jde dál.

# /etc/ssh/sshd_config.d/99-vlastni.conf

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
AuthenticationMethods publickey

AllowGroups ssh-users

LoginGraceTime 20
MaxAuthTries 3
MaxSessions 5
MaxStartups 10:30:60

AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no

ClientAliveInterval 300
ClientAliveCountMax 2

MaxStartups 10:30:60 znamená: nad 10 rozpracovaných přihlášení začni s pravděpodobností 30 % odmítat, nad 60 odmítej vše. Levná ochrana proti zahlcení.

AllowTcpForwarding no vypne tunely. Zapni je selektivně tam, kde jsou potřeba:

Match Group tunel
    AllowTcpForwarding yes
    PermitOpen 192.168.1.20:5432
    ForceCommand /usr/sbin/nologin

Uživatel v této skupině dostane tunel na databázi a nic jiného — ani shell. Match bloky musí být na konci souboru, protože platí až do dalšího Match.

Kontrola:

sshd -t                                    # syntaxe
sshd -T | sort                             # výsledná konfigurace
sshd -T -C user=martin,host=x,addr=10.0.0.5  # včetně vyhodnocení Match
systemctl reload ssh

Zádrhel na Ubuntu 24.04

Ubuntu 24.04 spouští SSH přes aktivaci soketem (ssh.socket). Důsledek: Port 2222 v sshd_config se ignoruje, protože port neotevírá sshd, ale systemd.

systemctl edit ssh.socket
[Socket]
ListenStream=
ListenStream=2222

Ten první prázdný řádek je nutný — vynuluje předchozí hodnotu, jinak se port jen přidá k dvaadvacítce.

Alternativně se dá socket vypnout a vrátit klasické chování:

systemctl disable --now ssh.socket
systemctl enable --now ssh.service

Nechoď do internetu vůbec

Nejlepší nastavení SSH je to, na které se zvenku nikdo nedostane. Za WireGuardem je hrubá síla mrtvá bez jediného pravidla ve firewallu, protože bez klíče WireGuard neodpoví ani jedním bajtem.

Přenos souborů

scp soubor server:/tmp/           # jednoduché
rsync -avz --progress dir/ server:/dir/    # lepší, přenáší jen rozdíly
sftp server                       # interaktivní
sshfs server:/data /mnt/data      # připojení jako disk (FUSE)

Poznámka k scp: jeho původní protokol byl plný nepříjemných překvapení (vzdálený server mohl ovlivnit, které soubory u tebe vzniknou) a OpenSSH 9.0 ho přepnul na SFTP. Většina lidí si toho nevšimla, ale některé exotické možnosti zmizely. Na cokoliv většího používej rsync — umí pokračovat a nepřenáší, co už tam je.

Diagnostika

ssh -v server        # co se děje
ssh -vvv server      # včetně vyjednávání algoritmů
ssh -G server        # výsledná konfigurace klienta

journalctl -u ssh -f            # log na serveru
/usr/sbin/sshd -d -p 2222       # sshd v ladicím režimu na jiném portu

Ten poslední příkaz stojí za zapamatování. Spustí druhého démona na jiném portu s výpisem všeho, obslouží jedno spojení a skončí. Ideální pro ladění bez rizika, že si zavřeš dveře.

Chyba Příčina
Permission denied (publickey) klíč není v authorized_keys, nebo se nepoužil ten správný — ověř ssh -v
častěji: špatná práva. ~ nebo ~/.ssh zapisovatelné pro skupinu
Too many authentication failures agent nabízí moc klíčů → IdentitiesOnly yes
no matching host key type found starý server s ssh-rsa (SHA-1). Aktualizuj server.
no matching key exchange method totéž, jen o kategorii vedle
Connection reset by peer hned fail2ban, firewall, nebo špatná verze protokolu
Connection timed out nedoletíš vůbec — firewall nebo směrování
REMOTE HOST IDENTIFICATION HAS CHANGED host key se změnil — zjisti proč
Broken pipe po nečinnosti NAT zahodil spojení → ServerAliveInterval
přihlášení trvá 10 s server dělá zpětný DNS překlad → UseDNS no

Nouzový přístup, když si zavřeš dveře: konzole u poskytovatele nebo hypervizoru, nebo připojení disku k jinému stroji a oprava sshd_config. Proto se při změnách vždycky drží druhé otevřené spojení, dokud si nové neověříš.

Chyby, o kterých je dobré vědět

Terrapin, CVE-2023-48795 (2023). Útočník uprostřed dokázal na začátku spojení nepozorovaně umazat pakety, protože se pořadová čísla nezapočítávala do ověření. Šlo tak potlačit vyjednání rozšíření a snížit bezpečnost sezení. Týkalo se to chacha20-poly1305 a CBC s EtM. Opravou je strict KEX od OpenSSH 9.6 — obě strany si zavedou pořadová čísla do výpočtu. ssh -v ti to potvrdí řádkem o kex-strict.

regreSSHion, CVE-2024-6387 (2024). Souběh v obsluze signálu při vypršení LoginGraceTime umožňoval vzdálené spuštění kódu jako root, bez přihlášení. Netriviálně zneužitelné, ale reálné. Ukázka toho, že drtivá většina zranitelností je v okolí, ne v kryptografii.

xz / liblzma, CVE-2024-3094 (2024). Do komprimační knihovny byl zaveden zadní vrátka, která přes distribuční záplatu pro systemd zasáhla sshd. Chytilo se to náhodou, protože si někdo všiml, že přihlášení trvá o půl vteřiny déle. Samotný OpenSSH liblzma nepoužívá — problém přinesla úprava distribuce.

Praktický závěr je nudný a pravdivý: aktualizuj. Všechny tři případy byly opravené dřív, než se objevily plošné útoky.

Tahák

# klíče
ssh-keygen -t ed25519 -a 100 -C "martin@notebook"
ssh-keygen -t ed25519-sk -O resident -O verify-required
ssh-copy-id -i ~/.ssh/id_ed25519.pub server
ssh-keygen -lf klic.pub                    # otisk
ssh-keygen -y -f klic > klic.pub           # veřejný z privátního

# známé hostitele
ssh-keygen -F server / -R server
ssh -o VerifyHostKeyDNS=yes server

# agent
ssh-add -l / -t 4h / -c / -D

# tunely
ssh -N -L 8080:localhost:80 server         # k sobě
ssh -N -R 8080:localhost:3000 server       # od sebe
ssh -N -D 1080 server                      # SOCKS
ssh -J brana cil                           # skok přes bránu

# certifikáty
ssh-keygen -s user_ca -I martin -n martin -V +8h klic.pub
ssh-keygen -L -f klic-cert.pub

# diagnostika
ssh -vvv server ; ssh -G server ; ssh -Q kex
sshd -t ; sshd -T ; ssh-audit server

Kam dál

Clone this wiki locally