Klucz, który nigdy nie opuszcza urządzenia
Klucz SSH przechowywany w ~/.ssh/id_ed25519 to plik o rozmiarze 411 bajtów. Bez hasła jest gotowy do użycia: skopiowanie tego pliku daje pełen dostęp do wszystkich serwerów, na których zarejestrowano odpowiadający klucz publiczny.
Ustawienie hasła na kluczu (-N "...") poprawia sytuację tylko częściowo. Na skompromitowanej maszynie keylogger przechwyci hasło podczas podawania. Kopie zapasowe w chmurze powielają problem, zamiast go eliminować.
YubiKey rozwiązuje to inaczej: klucza prywatnego nie ma w żadnym pliku. Żyje wewnątrz układu scalonego secure element, który wykonuje operacje kryptograficzne wewnętrznie i zwraca tylko wynik (podpis, odszyfrowany tekst, potwierdzenie autentykacji). Skradziony YubiKey bez znajomości PIN-u nie umożliwia złożenia żadnego podpisu, a po kilku błędnych próbach chip się blokuje.
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. Przepływ logowania wygląda następująco: po podaniu loginu i hasła strona wyświetla komunikat "dotknij swojego klucza bezpieczeństwa", użytkownik wkłada YubiKey do USB i dotyka metalowego dysku. Nie ma kodu do przepisywania, SMS-a ani cyfr z aplikacji mobilnej: po dotknięciu strona przeładowuje się z aktywną sesją.
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 do przeglądarki. Użytkownik nie widzi żadnego ciągu znaków. Każde logowanie ma inny challenge, więc atak powtórzeniowy (replay attack) jest niemożliwy.
Klucz publiczny rejestruje się w serwisie raz, klucz prywatny zostaje na urządzeniu na zawsze.
Protokół jest 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: hasło nie jest wymagane. Przepływ logowania ogranicza się do podania loginu (przeglądarka może sama wykryć dostępne passkeye), dotknięcia YubiKey i wpisania PIN-u raz na sesję. Zamiast dwóch kroków (hasło + klucz) wystarczy jeden gest. Trzy istotne zmiany względem U2F:
- Brak hasła: FIDO2 może być jedynym czynnikiem (passwordless), nie tylko drugim.
- PIN: w U2F samo dotknięcie wystarczyło; w FIDO2 chip wymaga PIN-u wpisywanego raz na podpięcie klucza, co czyni skradziony YubiKey bezużytecznym.
- Odporność na phishing: chip przechowuje domenę, dla której klucz został zarejestrowany, i odmówi podpisu dla
g00gle.comnawet gdy strona wygląda identycznie.
Mechanizm passwordless to podstawa oferty passkey w produktach Microsoftu, Google i Apple.
Passkey — termin wprowadzony przez FIDO Alliance (promowany przez Apple/Google/Microsoft) na discoverable credential FIDO2 z ergonomicznym UX. Technicznie to ten sam standard, z rozróżnieniem na synced passkeys (synchronizowane między urządzeniami, np. iCloud Keychain) i device-bound passkeys (przywiązane do jednego urządzenia, np. YubiKey). Z perspektywy użytkownika passkey zastępuje hasło uwierzytelnieniem odciskiem palca, Face ID lub PIN-em. Passkey może być przechowywany na YubiKey, w iCloud Keychain, w Google Password Manager lub synchronizowany między tymi miejscami. Zalety: eliminacja haseł, odporność na phishing, możliwość działania offline. Ograniczenie: synced passkey (np. w iCloud Keychain) uzależnia bezpieczeństwo od bezpieczeństwa konta chmurowego (Apple ID) i nie jest już device-bound. Gwarancję, że klucz prywatny nigdy nie opuści chipa, daje wyłącznie device-bound passkey na YubiKey.
Resident Key (Discoverable Credential) — klucz FIDO2 przechowywany w całości na YubiKey. "Zwykły" (non-resident) klucz FIDO2 wymaga pliku handle na dysku komputera, bo YubiKey trzyma tylko seed do wyprowadzenia klucza. Praktyczna różnica: z resident key można wpiąć YubiKey w dowolny komputer (obcy laptop, kiosk, świeżo zainstalowany system), zalogować się do GitHuba lub wykonać ssh-keygen -K i uzyskać dostęp do zarejestrowanych kont. Bez resident key konieczny jest plik-handle z poprzedniej maszyny. Resident key zapewnia pełną mobilność, ale liczba slotów jest ograniczona (25–100, zależnie od wersji firmware), dlatego powinien być zarezerwowany dla kluczowych serwisów.
Algorytmy podpisu
Wszystko, co YubiKey robi w tej sekcji, opiera się na kryptografii asymetrycznej: para kluczy składa się z prywatnego (tajny, przechowywany na chipie) i publicznego (jawny, rejestrowany na serwerze lub w authorized_keys). Cokolwiek zostanie podpisane kluczem prywatnym, każdy może zweryfikować kluczem publicznym; cokolwiek zaszyfrowane kluczem publicznym, odszyfruje wyłącznie właściciel klucza prywatnego. Matematycznie można 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 pojawiają się przy konfiguracji YubiKey: od najnowszego i 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) — 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 odbywa się przez serwery Yubico. W praktyce funkcja ta rzadko jest potrzebna (w kolejnych częściach serii zostanie wyłączona); jedyną jej zaletą jest działanie od razu po wyjęciu z pudełka.
TOTP (Time-based OTP, RFC 6238) — 6-cyfrowy kod regenerowany co 30 sekund, taki sam mechanizm jak 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 kodów wymagana jest aplikacja Yubico Authenticator, ponieważ 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
Przykładowy przepływ: logowanie do GitHuba przy użyciu passkey na YubiKey.
- Otwarcie
github.com/logini kliknięcie "Sign in with passkey". - Serwer GitHuba generuje losowe wyzwanie (challenge): 32 bajty losowych danych wysyłane do przeglądarki.
- Przeglądarka prosi YubiKey o podpis. Wyświetlany jest komunikat "dotknij klucza", opcjonalnie z prośbą o PIN (raz na sesję).
- YubiKey weryfikuje, czy posiada resident key dla
github.com. Jeśli tak, podpisuje challenge kluczem prywatnym wewnątrz chipa. Klucz prywatny nigdy nie opuszcza urządzenia. - Podpisany challenge trafia do przeglądarki, a stamtąd na serwer GitHuba.
- Serwer weryfikuje podpis kluczem publicznym zapisanym na koncie. Po pomyślnej weryfikacji ustawia ciasteczko sesji i przyznaje dostęp.
sequenceDiagram
participant U as Użytkownik + YubiKey
participant S as github.com
S->>U: challenge
U->>S: podpisany challenge
S->>U: sesja aktywna
- Challenge jest losowy: każda sesja ma inny. Atak powtórzeniowy (replay attack) jest niemożliwy.
- YubiKey weryfikuje domenę żądania. Phishing na
g1thub.comnie zadziała: chip zna prawdziwą domenę z momentu rejestracji i odmówi podpisu dla innej. - Klucz prywatny nie opuszcza chipa. Serwer otrzymuje tylko podpis i potwierdza obecność klucza prywatnego, nie jego wartość.
- PIN i dotyk są lokalne. Nie są nigdzie przesyłane i nie mogą zostać przechwycone przez sieć.
Ten sam wzorzec (challenge, podpis na chipie, weryfikacja kluczem publicznym) działa w SSH, w git push przez SSH oraz w sudo z PAM-U2F. Różnice dotyczą wyłącznie warstwy transportu.
Kiedy to ma sens
1. Praca z wielu maszyn: laptop, desktop, serwery
Klasyczny problem: klucz SSH przechowywany w pliku wymaga albo kopiowania między maszynami (ryzyko wycieku), albo utrzymywania osobnego klucza na każdej (rozrost authorized_keys). YubiKey eliminuje oba warianty.
- Klucz prywatny nigdy nie istnieje na dysku — nie ma czego kopiować.
- Podłączenie YubiKey w dowolnym komputerze i wykonanie
ssh-keygen -Kdaje dostęp do handle'y. 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
Organizacja wymaga kryptograficznej gwarancji, że sesję otworzył człowiek z fizycznym kluczem, a nie skrypt operujący 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.