Klucz, który nigdy nie opuszcza urządzenia
Twój klucz SSH leży w ~/.ssh/id_ed25519. Plik ma 411 bajtów. Bez hasła — gotowy do użycia. Ktoś, kto skopiuje ten plik, jest tobą dla każdego serwera, na który masz dostęp.
Hasło na kluczu (-N "...") tylko trochę poprawia. Jeśli laptop jest skompromitowany, keylogger przechwyci hasło. Backup w chmurze? Tylko powiela problem.
YubiKey rozwiązuje to inaczej: klucza prywatnego nie ma w żadnym pliku. Żyje w wewnątrz układu scalonego trusted module, który wykonuje operacje kryptograficzne wewnętrznie i zwraca tylko wynik — podpis, odszyfrowany tekst, potwierdzenie autentykacji. Nawet jeśli ktoś ukradnie YubiKey, bez PIN-u nie podpisze niczego. A PIN można wpisać błędnie tylko kilka razy, zanim chip się zablokuje.
To pierwszy post z serii o YubiKey.
Teraz: Wstęp, pokazanie co możesz zyskać i jakie pojęcia musisz znać oraz kiedy taki klucz ma sens.
W kolejnych odcinkach: modele, instalacja narzędzi, SSH, podpisywanie commitów, szyfrowanie sekretów w GIT.
Architektura urządzenia
YubiKey 5 to nie jest jeden klucz. To kilka niezależnych appletów (aplikacji na chipie), z których każda realizuje inny standard. Każda ma własną pamięć, własny PIN i własny protokół komunikacji. Dokładnie tak samo, jak na karcie kredytowej lub karcie SIM. Wszystkie applety są wzajemnie izolowane, działają jednocześnie i mają niezależną konfigurację i pamięć.
flowchart TB
YK([YubiKey 5])
YK --> F[FIDO2 / WebAuthn]
YK --> P[OpenPGP card]
YK --> V[PIV smart card]
YK --> O[OATH]
YK --> T[OTP / Challenge-Response]
F -->|"passkeys, ed25519-sk"| FU[SSH FIDO2, logowanie www]
P -->|"RSA, ed25519, cv25519"| PU[GPG sign/encrypt, SSH przez gpg-agent, podpisy commitów]
V -->|"X.509, klucze prywatne w slotach"| VU[Smart card login, age-plugin-yubikey]
O -->|"TOTP, HOTP, do 32 kont"| OU[2FA: GitHub, Google, AWS]
T -->|"HMAC-SHA1, static password"| TU[LUKS unlock, KeePassXC, fallback]
Słownik pojęć
Standardy uwierzytelniania webowego
FIDO U2F (Universal 2nd Factor, ~2014) — pierwszy szeroko wdrożony standard sprzętowych kluczy. Służy wyłącznie jako drugi faktor, po haśle. Jeśli kiedyś logowałeś się do Google'a, Facebooka czy Dropboxa z włączonym 2FA na klucz: wpisujesz login i hasło, strona prosi "dotknij swojego klucza bezpieczeństwa", wkładasz YubiKey do USB i kładziesz palec na metalowym dysku. I to wszystko — żadnego kodu do przepisywania, żadnego SMS-a, żadnego wpisywania szóstek z aplikacji. Po dotknięciu strona po prostu się przeładowuje i jesteś zalogowany.
Pod spodem przeglądarka komunikuje się z kluczem binarnie po protokole HID (USB-HID, NFC albo Bluetooth). Wysyła do chipa losowe wyzwanie (challenge) razem z identyfikatorem strony, chip podpisuje je kluczem prywatnym i zwraca podpis z powrotem do przeglądarki. Użytkownik nigdy nie widzi żadnego ciągu znaków — widzi tylko, że po dotknięciu jest dalej. Każde logowanie ma inny challenge, więc replay attack jest niemożliwy.
Klucz publiczny rejestrujesz w serwisie raz, klucz prywatny zostaje na urządzeniu na zawsze.
Protokół, wciąż obsługiwany przez YubiKey ze względu na wsteczną kompatybilność, ale wszystkie nowe wdrożenia używają FIDO2.
FIDO2 / WebAuthn (2019) — następca U2F. Połączenie standardu po stronie urządzenia (CTAP2 — protokół klient ↔ klucz) i przeglądarkowego API (WebAuthn — JS-owe API rejestracji i logowania). Kluczowa różnica jest taka, że w ogóle nie musisz wpisywać hasła. Wchodzisz na stronę, wpisujesz login (a często nawet nie — przeglądarka sama wykrywa dostępne passkeye), strona pyta "zaloguj się kluczem bezpieczeństwa", dotykasz YubiKey, wpisujesz PIN raz na sesję i jesteś w środku. Nie ma już dwóch kroków (hasło + klucz) — jest jeden gest. Drugą zauważalną zmianą jest PIN: w U2F samo dotknięcie wystarczyło, w FIDO2 chip wymaga PIN-u (wpisywanego raz na podpięcie klucza), więc skradziony YubiKey jest bezużyteczny. Trzecią — odporność na phishing: chip pamięta domenę, na której zarejestrowałeś klucz, i odmówi podpisu dla g00gle.com, nawet jeśli strona wygląda identycznie.
FIDO2 może być jedynym czynnikiem (passwordless), nie musi być drugim — i właśnie to robią dziś Microsoft, Google i Apple, gdy proszą cię o "dodanie passkeya".
Passkey — nazwa marketingowa Apple/Google/Microsoft na resident key FIDO2 z ergonomicznym UX. Technicznie to ten sam standard. Z perspektywy użytkownika passkey to po prostu "zaloguj się odciskiem palca / Face ID / PIN-em z telefonu" zamiast hasła. Jeśli kiedyś klikałeś "Sign in with passkey" na GitHubie i telefon poprosił cię o odcisk palca — to jest właśnie to. Może żyć na YubiKey, w iCloud Keychain, w Google Password Manager albo synchronizować się między nimi. Co ci to daje: nie pamiętasz hasła, nie wpada na phishing, działa offline. Czego nie daje: jeśli passkey siedzi w iCloud Keychain, jego bezpieczeństwo zależy od bezpieczeństwa twojego Apple ID — nie jest to już hardware-bound. Dopiero passkey na YubiKey daje gwarancję, że klucz prywatny nigdy nie opuścił chipa.
Resident Key (Discoverable Credential) — klucz FIDO2 przechowywany w całości na YubiKey. "Zwykły" (non-resident) klucz FIDO2 wymaga pliku-handle'a na dysku komputera, bo YubiKey trzyma tylko seed do wyprowadzenia klucza. Z perspektywy użytkownika różnica jest taka: z resident key możesz wpiąć YubiKey w dowolny komputer (cudzy laptop, kiosk, świeżo zainstalowany system), zalogować się do GitHuba czy zrobić ssh-keygen -K i masz dostęp do wszystkich swoich kont. Bez resident key — potrzebujesz mieć ze sobą plik-handle z poprzedniej maszyny. Co ci to daje: pełną mobilność, "klucz w kieszeni = tożsamość w kieszeni". Czego nie daje: nielimitowanej liczby kont — jest twardy limit slotów (25–100, w zależności od firmware'u), więc resident key zarezerwuj dla naprawdę istotnych serwisów.
Algorytmy podpisu
Wszystko, co YubiKey robi w tej sekcji, opiera się na kryptografii asymetrycznej: masz parę kluczy — prywatny (tajny, siedzi na chipie) i publiczny (jawny, leży na serwerze albo w authorized_keys). Cokolwiek podpiszesz kluczem prywatnym, każdy może zweryfikować kluczem publicznym; cokolwiek zaszyfrujesz kluczem publicznym, tylko właściciel prywatnego rozszyfruje. Brzmi prosto, ale matematycznie da się to zrealizować na kilka sposobów — każdy z innym balansem szybkości, długości klucza i odporności na ataki. Poniżej cztery algorytmy, które realnie spotkasz przy konfiguracji YubiKey, od najnowszego i najbardziej preferowanego po starsze warianty zachowane dla kompatybilności.
ed25519 — algorytm podpisu cyfrowego oparty na krzywej eliptycznej Curve25519. Szybki, bezpieczny, ma krótkie klucze (32 bajty na klucz publiczny). W kontekście SSH typ klucza nazywa się ssh-ed25519 — preferowany wybór dla wszystkich nowych kluczy.
ed25519-sk — wariant ed25519 dla SSH, gdzie operacja podpisu jest delegowana do zewnętrznego security key (-sk). Klucz prywatny nigdy nie istnieje na komputerze; SSH pyta urządzenie FIDO2 o podpis przez bibliotekę libfido2.
RSA-4096 — klasyczny algorytm w GPG. Wciąż bezpieczny, ale klucze są długie (~3 kB na publiczny), operacje wolniejsze. Dla nowych konfiguracji GPG na YubiKey 5 wybierz raczej ed25519.
Smart card / OpenPGP
OpenPGP — standard szyfrowania i podpisywania. YubiKey realizuje OpenPGP card specification — chip zachowuje się jak fizyczna karta procesorowa dla GPG. Trzyma do trzech subkluczy: Signature, Encryption, Authentication (może służyć jako klucz SSH przez gpg-agent). Daemon scdaemon jest mostem między GnuPG a fizycznym chipem.
PIV (Personal Identity Verification) — standard NIST SP 800-73, pierwotnie dla amerykańskich agencji rządowych. Definiuje cztery sloty na certyfikaty X.509 (9a Authentication, 9c Signature, 9d Key Management, 9e Card Authentication). YubiKey implementuje PIV i można pod niego podpiąć biblioteki PKCS#11 — w praktyce: smart card login do Windows, autoryzacja VPN, age-plugin-yubikey do szyfrowania sekretów.
Hasła jednorazowe i czasowe
OTP (One-Time Password) To ten irytujący mechanizm, który wpisuje bzdury, gdy przypadkiem dotkniesz klucza w aplikacji obsługującej tekst. W nomenklaturze Yubico to konkretnie Yubico OTP — własnościowy protokół. Po dotknięciu klucza emulowana klawiatura wpisuje 44-znakowy ciąg w stylu ccccccvrlhknbujfgdeelrid.... Walidacja przez serwery. W praktyce rzadko go potrzebujesz — wyłączamy, jego zaletą jest, że działa out-of-box.
TOTP (Time-based OTP, RFC 6238) — 6-cyfrowy kod regenerowany co 30 sekund. To, co widzisz w Google Authenticatorze. YubiKey ma do 32 slotów na seedy TOTP w applecie OATH. Kody generuje chip — seed nigdy nie opuszcza urządzenia. Do wyświetlania potrzebujesz aplikacji Yubico Authenticator, bo na YubiKey nie ma ekranu.
HOTP (HMAC-based OTP, RFC 4226) — wariant OTP z licznikiem zamiast czasu. Rzadziej używany.
Static Password — YubiKey może emitować stały ciąg znaków przy dotknięciu. System widzi to, jak wpisanie hasła z klawiatury. Nie jest kryptograficznie bezpieczny, ale lepszy niż 40-znakowe hasło zapisywane na kartce.
Challenge-Response — YubiKey przyjmuje na wejściu challenge (ciąg bajtów), przetwarza algorytmem HMAC-SHA1 z zapisanym sekretem i zwraca response. Używane przez yubikey-luks i KeePassXC.
Jak to działa krok po kroku
Przeanalizujmy przykład: logujesz się do GitHuba przy użyciu passkey'a na YubiKey.
- Wchodzisz na
github.com/logini klikasz "Sign in with passkey". - Serwer GitHuba generuje losowe wyzwanie (challenge) — 32 bajty losowych danych — i wysyła je do przeglądarki.
- Przeglądarka prosi YubiKey o podpis. Wyświetla "dotknij klucza", ewentualnie pyta o PIN (raz na sesję).
- YubiKey sprawdza, czy ma resident key dla
github.com. Jeśli tak — podpisuje challenge kluczem prywatnym wewnątrz chipa. Klucz prywatny nigdy nie opuszcza urządzenia. - Podpisany challenge wraca do przeglądarki, a stamtąd na serwer GitHuba.
- Serwer weryfikuje podpis kluczem publicznym, który masz zapisany na koncie. Jeśli się zgadza — ustawia ciasteczko sesji i jesteś zalogowany.
sequenceDiagram
participant U as Ty + YubiKey
participant S as github.com
S->>U: challenge
U->>S: podpisany challenge
S->>U: zalogowany
- Challenge jest losowy — każda sesja ma inny. Replay attack niemożliwy.
- YubiKey weryfikuje, że żądanie pochodzi z
github.com. Phishing nag1thub.comnie zadziała — chip zna prawdziwy domain z momentu rejestracji i odmówi podpisu dla innego. - Klucz prywatny nie opuszcza chipa. Serwer dostaje tylko podpis i wie, że ktoś trzymający odpowiadający klucz prywatny był obecny.
- PIN i dotyk są lokalne. Niewysyłane nigdzie. Nie da się zhacować przez sieć.
Ten sam wzorzec — challenge, podpis na chipie, weryfikacja kluczem publicznym — działa w SSH, w git push przez SSH, w sudo z PAM-U2F. Różnice tylko w warstwie transportu.
Kiedy to ma sens
1. Praca z wielu maszyn — laptop, desktop, serwery
Klasyczny problem: klucz SSH leży w pliku, więc albo kopiujesz go między maszynami (ryzyko), albo masz osobny klucz na każdej (bałagan w authorized_keys). Z YubiKey ani jedno, ani drugie.
- Klucz prywatny nigdy nie istnieje na dysku — nie ma czego kopiować.
- Wpinasz YubiKey w dowolny komputer, robisz
ssh-keygen -Ki masz swoje handle'e. Działa na laptopie, desktopie, obcym sprzęcie awaryjnym, w biurze. - Po odłączeniu klucza nie zostaje żaden ślad na maszynie.
- Skradziony laptop bez fizycznego klucza i PIN-u nie daje dostępu do żadnego serwera.
2. Podpisywane commity i SSH do GitHuba
Verified commits + bezpieczne SSH:
- Klucz GPG na YubiKey podpisuje commity. Zielona plakietka Verified w GitHubie.
- Ten sam klucz GPG (subkey Authentication) służy jako klucz SSH do
git push. - TOTP do logowania na GitHub/GitLab — w applecie OATH na tym samym kluczu.
- Jedno urządzenie zastępuje: klucz SSH + Google Authenticator + GPG sign.
3. Zespół z polityką bezpieczeństwa
Firma chce kryptograficznej gwarancji, że logował się człowiek z fizycznym kluczem, a nie skrypt z wykradzionym plikiem:
sshd_configograniczaPubkeyAcceptedAlgorithmstylko dosk-ssh-ed25519@openssh.com.- W
authorized_keyskażdy klucz oznaczonyverify-required— wymuszony PIN + touch. - Brak fallbacku do haseł.
- Wyciek klucza prywatnego niemożliwy, bo on nie istnieje poza chipem.