1 Punkte von GN⁺ 4 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Sicherheitstoken signieren innerhalb des Geräts, ohne den privaten Schlüssel nach außen zu geben, und verlangen eine physische Aktion des Nutzers, sodass es für Remote-Angreifer schwer ist, beliebige Signaturen zu erzeugen
  • Sie lassen sich für SSH-Authentifizierung, U2F, passwortlose lokale Anmeldung, sudo und das Signieren von git-Commits verwenden, und die eingebauten Sicherheitsmodule moderner Laptops und Smartphones können einen YubiKey ersetzen
  • Die mit ssh-keygen -t ed25519-sk erzeugte „Privatschlüssel“-Datei ist kein echter privater Schlüssel, sondern ein Handle, das auf den Schlüssel im Token zeigt; mit demselben Token kann man auf anderen Computern dieselbe SSH-Schlüsseldatei erzeugen
  • Auf dem MacBook ließ sich das Secure Element als SSH-Schlüssel einrichten, sodass Touch-ID-basierte SSH-Anmeldungen möglich waren; für git-Commit-Signaturen war statt eines Dateipfads ssh-agent und ein user.signingKey im Format key:: nötig
  • Sicherheitstoken erlauben bei Verlust keine Wiederherstellung des privaten Schlüssels und bergen ein Usability-Risiko durch häufiges Tippen; auf Windows-Laptops konnte Windows Hello die Nutzung des SSH-Schlüssels per Gesichtserkennung, Fingerabdruck oder PIN bestätigen

Vorteile und Grenzen von Sicherheitstoken

  • Die Kernarchitektur gegen Remote-Angriffe

    • Ein Sicherheitstoken ist ein Gerät, das ein Schlüsselpaar aus privatem und öffentlichem Schlüssel im Gerät hält; der öffentliche Schlüssel lässt sich leicht auslesen, aber der private Schlüssel verlässt das Gerät nicht
    • Schickt man ein zu signierendes Datenpaket an das Gerät, wird es darin mit dem privaten Schlüssel signiert; normalerweise ist dafür zusätzlich eine physische Aktion des Nutzers nötig, etwa das Drücken eines blinkenden Touch-Buttons
    • Selbst wenn ein Remote-Angreifer Zugriff auf den Computer erhält, kann das Sicherheitstoken keine beliebigen Signaturen erzeugen, solange der Nutzer nicht in der realen Welt aktiv wird; deshalb wirkt es sicherer, als ein vollständiges SSH-Schlüsselpaar als Dateien im Verzeichnis ~/.ssh zu speichern
    • Mit SoloKeys und Nitrokeys gibt es auch Optionen für Nutzer, die FOSS-Firmware möchten
    • Hochwertigere Sicherheitstoken ergänzen biometrische Funktionen wie eingebaute Fingerabdruckleser, aber der Kern bleibt, dass der private Schlüssel das Gerät nicht verlässt
  • Risiken bei der Benutzbarkeit

    • Wenn sich Nutzer daran gewöhnen, bei jedem Blinken des Sicherheitstokens zu drücken, reagieren sie womöglich auch auf bösartige Anfragen gedankenlos
    • Bei fortlaufenden Signaturvorgängen, in denen das Token wiederholt gedrückt werden muss, ist es schwer, eine zusätzliche blinkende Anfrage tatsächlich zu bemerken
    • Apple und Microsoft nutzen in Authenticator-Apps auf Smartphones ein Verfahren, bei dem bei jedem Zugriffsversuch ein zufälliger Zahlencode angezeigt wird, den der Nutzer eingeben muss; das ist jedoch umständlich und verringert den Usability-Vorteil von Sicherheitstoken gegenüber Apps wie Authy oder Google Authenticator mit TOTP
  • Verlust und Backup-Probleme

    • Geht ein Sicherheitstoken verloren, ist der betreffende private Schlüssel dauerhaft weg und lässt sich nicht sichern
    • Um das Risiko zu vermeiden, aus mehreren Konten ausgesperrt zu werden, sollte man beim Kauf von Sicherheitstoken mindestens zwei Geräte anschaffen und beim selben Dienst registrieren
    • Als Alternative gibt es Backup- und Wiederherstellungsverfahren wie BIP 39, bei denen ein privater Schlüssel in eine für Menschen lesbare Wortliste umgewandelt und notiert wird
    • Wenn ein privater Schlüssel die Secure Enclave verlassen kann, werden auch Phishing-Angriffe möglich, die Nutzer dazu verleiten, die Wortliste an der falschen Stelle einzugeben
    • Wenn die Möglichkeit, alle Sicherheitstoken zu verlieren, große Sorgen bereitet, kann eine BIP-39-Wortliste das letzte Mittel sein, um den Systemzugang wiederherzustellen

Sicherheitstoken mit SSH und git verwenden

  • SSH-Privatschlüssel im Sicherheitstoken speichern

    • Normalerweise erzeugt ssh-keygen ein Dateipaar, das den vollständigen privaten Schlüssel enthält
    • Um den privaten Schlüssel in einem Sicherheitstoken zu speichern, installiert man gemäß Yubicos FIDO/U2F-Anleitung libfido2 und führt mit eingestecktem Sicherheitstoken ssh-keygen -t ed25519-sk aus
    • Dabei wird ebenfalls ein Dateipaar erzeugt, aber die „Privatschlüssel“-Datei ist kein echter privater Schlüssel, sondern ein Handle auf den privaten Schlüssel im Sicherheitstoken
    • Führt man ssh-keygen -t ed25519-sk mit demselben Sicherheitstoken erneut aus, kann man auf jedem Computer dieselben privaten/öffentlichen Schlüsseldateien erzeugen; der SSH-Zugang wandert also mit dem Sicherheitstoken statt an eine bestimmte Datei auf einem bestimmten Computer gebunden zu sein
  • git-Authentifizierung und Commit-Signaturen

    • Rund 90 % der Situationen, in denen das Sicherheitstoken gedrückt werden muss, entstehen durch git-Nutzung
    • git-Forges implementieren SSH-Authentifizierung für Push- und Pull-Vorgänge; lädt man die oben erzeugte Datei id_ed25519_sk.pub hoch, lässt sich das Schlüsselpaar des Sicherheitstokens zulassen
    • git unterstützt auch SSH-Schlüssel für Commit-Signaturen; folgt man der GitHub-Dokumentation Einrichten eines Signaturschlüssels mit einem SSH-Schlüssel und führt anschließend git config --global commit.gpgsign true aus, werden alle Commits automatisch signiert
    • Damit eine git-Forge die Commits als eigene Signaturen erkennt, muss der öffentliche Schlüssel nochmals hochgeladen werden; dieses Feld ist meist vom Feld für SSH-Authentifizierung getrennt
  • Unbequemlichkeiten bei Commit-Signaturen

    • Wenn man eine lange Commit-Liste rebased, müssen alle Commits erneut signiert werden
    • Bei einem YubiKey mit Fingerabdruckleser war die Fehlerrate der Fingerabdruckerkennung zu hoch, um Dutzende Commits hintereinander zu signieren, sodass die Nutzung aufgegeben wurde
    • Im „rebase/amend-zentrierten“ Wrapper jujutsu gibt es einen Ansatz, Commits erst beim Push zu signieren
  • Lokale Linux-Anmeldung und sudo

Das Secure Element eines MacBook als SSH-Schlüssel verwenden

  • Wenn ein Sicherheitstoken dauerhaft im USB-C-Port steckt, ragt es wie ein kleiner Hebel hervor, der bei versehentlichem Fallenlassen oder Anstoßen sowohl Port als auch Token beschädigen kann
  • Auf einem MacBook Air M1 von 2020 wurde nach der Anleitung von Arian van Putten das eingebaute Sicherheitselement als SSH-Schlüssel eingerichtet
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""
  • Dieser Befehl erzeugt ein privates/öffentliches Schlüsseldateipaar id_ecdsa_sk_rk, das anschließend in das Verzeichnis ~/.ssh verschoben wird
  • Auch hier ist die Privatschlüsseldatei kein echter privater Schlüssel, sondern ein Handle auf den Schlüssel im Gerät und kann daher in einer Form öffentlich eingefügt werden
  • Um den öffentlichen Schlüssel auf einem Homelab-Server als authorized key hinzuzufügen, führt man Folgendes aus
ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname>
  • Danach wird ~/.ssh/config um folgende Einstellungen ergänzt
Host *
  IdentityFile ~/.ssh/id_ecdsa_sk_rk
  SecurityKeyProvider=/usr/lib/ssh-keychain.dylib
  • Führt man ssh <server nickname> aus, zeigt macOS vor der Anmeldung automatisch eine Fingerabdruckabfrage an, danach läuft die SSH-Anmeldung normal weiter

git-Commit-Signaturen mit dem MacBook-Secure-Element

  • Selbst wenn man git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk setzt und die Datei .ssh/allowed_signers aktualisiert, funktionieren git-Commit-Signaturen nicht sofort
  • git scheitert beim Signieren von Commits und gibt einen Fehler wie device not found? aus
error: Signing file /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO
Confirm user presence for key ECDSA-SK SHA256:oQDA2SNYb2MoSQcxJVSmWyAeAWPqMp7rxliBRfi87as
Couldn't sign message: device not found?
Signing /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO failed: device not found?

fatal: failed to write commit object
  • Die Lösung besteht darin, ssh-agent zu verwenden, statt direkt auf die Dateien im Verzeichnis ~/.ssh zu verweisen
  • Gemäß dem obigen Tutorial wird das Schlüsselpaar mit folgendem Befehl bei ssh-agent registriert
ssh-add -K -S /usr/lib/ssh-keychain.dylib
  • Danach wird in user.signingKey nicht ein Dateipfad eingetragen, sondern der Schlüssel selbst, also der Inhalt von ~/.ssh/id_ecdsa_sk_rk.pub mit vorangestelltem key::, in ~/.gitconfig
[user]
	name = Andrew Helwer
	signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"
  • Nach dieser Konfiguration ließen sich Dateien mit dem Schlüssel im Secure Element des MacBook signieren und auf eine GitLab-Pages-Seite pushen

Ergebnisse unter Windows und Linux

  • Auch auf einem vom Unternehmen bereitgestellten Windows-Laptop wurde ein kurzer Test durchgeführt
winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk
  • Auch dieser Befehl erzeugte ein privates/öffentliches Schlüsseldateipaar; bei SSH-Verbindungen akzeptierte der Standard-Login-Ablauf von Windows Hello Gesichtserkennung, Fingerabdruck oder PIN
  • Unter Linux konnte dies nicht demonstriert werden, weil kein Zugriff auf einen Laptop mit angebundenem Secure Element und vergleichbarer Bestätigung der tatsächlichen Nutzerpräsenz verfügbar war

1 Kommentare

 
GN⁺ 4 시간 전
Lobste.rs-Kommentare
  • Großartiger Artikel, und schon allein darauf hinzuweisen, dass so etwas möglich ist, ist sehr wertvoll
    Ich persönlich habe zwar nicht die richtige Library-Version gefunden, um das zum Laufen zu bringen, aber ich habe herausgefunden, dass 1Password 8 SSH-Schlüssel sicher speichern kann und der Agent das Entsperren des Schlüssels per biometrischer Authentifizierung unterstützt
    Deshalb kann ich jetzt allein mit dem Finger git-Arbeit erledigen und mich auch bei SSH-Hosts anmelden
    Anleitung: https://developer.1password.com/docs/ssh/get-started/

  • Das wirkt wie nur für Mac

    • Ich kann bei der Arbeit einen aktuellen Windows-Laptop nutzen und habe OpenSSH daher so eingerichtet, dass es mit Windows Hello zusammenarbeitet:
      winget install Microsoft.OpenSSH.preview  
      ssh-keygen -t ecdsa-sk  
      
      Danach funktionierte es wie früher, und jedes Mal, wenn ich per Schlüssel irgendwo eine SSH-Verbindung aufgebaut habe, lief der normale Windows-Hello-Ablauf, bei dem ich Fingerabdruck, Gesichtserkennung oder PIN verwenden konnte
      Ein Linux-System mit einem solchen Sicherheitselement konnte ich nicht ausprobieren, und meine Linux-Workstation hat zwar ein V1-TPM, aber ich weiß nicht wirklich, wie man sicherstellt, dass Signaturvorgänge nur nach tatsächlicher Bestätigung der Benutzeranwesenheit ausgeführt werden
      Vielleicht kann das jemand mit einem Linux-Laptop wie Framework ausprobieren. Möglicherweise funktioniert es sogar unter Asahi tatsächlich
    • Würde ich auch fast sagen. Ich weiß nicht, ob es unter Linux oder Windows eine TPM2-FIDO-Emulationsschicht gibt
  • Was genau befindet sich also in der bereitgestellten private key-Datei?

    • @wrs hat zwar schon geantwortet, aber der Teil ssh:, also die Anwendung, entspricht der origin eines Passkeys und ist nützlich, wenn man resident keys pro Host oder Domain anlegt
      Ich nutze das zum Beispiel, um selbst auf demselben physischen Yubikey Schlüssel nach Einsatzzweck zu trennen
      flags legt fest, wie die Hardware mit dem Schlüssel umgehen soll [1]. Der Agent kann zusätzlich eigene Einschränkungen hinzufügen
      Technisch gesehen kann man im FIDO-Schlüssel auch andere Blobs oder Erweiterungen speichern, und bei meinem früheren Arbeitgeber haben wir das einmal genutzt, um zusammen mit der Authentifizierung zusätzliche Anmeldeinformationen wie einen öffentlichen X.509-Schlüssel zu übergeben. Ziemlich eleganter Ansatz
      [1]
      #define SSH_SK_USER_PRESENCE_REQD  0x01  
      #define SSH_SK_USER_VERIFICATION_REQD  0x04  
      #define SSH_SK_FORCE_OPERATION    0x10  
      #define SSH_SK_RESIDENT_KEY    0x20  
      
    • Laut Claude und verifiziert mit openssh_key_parser ist die Struktur wie folgt
      Der äußere Wrapper enthält den Magic-Wert openssh-key-v1\0, cipher=none, kdf=none, ist also kein Chiffrat
      Der 74-Byte-Blob des öffentlichen Schlüssels enthält den Schlüsseltyp sk-ssh-ed25519@openssh.com, den 32-Byte-Ed25519-Punkt fdcce889…03e7852b und die Anwendung ssh:; dieser Wert trennt die FIDO-Credentials von SSH und WebAuthn per Namespace
      Der private Abschnitt ist 248 Byte groß und wegen cipher=none Klartext. Enthalten sind der Zufallswert checkint1 == checkint2 == 0x46744267, der wiederholte Schlüsseltyp und öffentliche Schlüssel, die Anwendung ssh: sowie flags: 0x01
      Dieses Flag bedeutet USER_PRESENCE_REQUIRED, also ist eine Berührung erforderlich, aber keine PIN/Benutzerverifizierung, und es ist ein nicht-residenter Schlüssel
      key_handle ist eine undurchsichtige 128-Byte-Credential-ID, die an authenticatorGetAssertion übergeben wird und die das Gerät intern auflöst, um den Ed25519-Seed wiederherzustellen
      Daneben gibt es ein leeres reserved, den Kommentar ahelwer@ah-mbair.local und das Padding 01 02 03
    • Wenn man es in einen base64-Decoder steckt, kommt Folgendes heraus

      openssh-key-v1����none���none����������J���sk-ssh-ed25519@openssh.com��� 盘˪<F$KW+���ssh:���FtBgFtBg���sk-ssh-ed25519@openssh.com��� 盘˪<F$KW+���ssh:���fІpF$D8"&0[X 'L=Ev ')BjM]$}rTv6Z+p9O8ݹ%V* f.|қ.%I{9 .W !D"8N ai*W�y53 �������ahelwer@ah-mbair.local
      Darin stecken die Standardversion des Schlüssels v1, der Schlüsseltyp sk-ssh-ed25519@openssh.com, der aus irgendeinem Grund wiederholt wird, und auch der menschenlesbare Schlüsselname ahelwer@ah-mbair.local
      Der Rest dürften OpenSSH-Flags sein, etwa ob eine PIN oder die Bestätigung der Benutzeranwesenheit erforderlich ist, sowie ein Handle-GUID, das OpenSSH zusammen mit der Challenge an die FIDO/U2F-API senden kann
      OpenSSH kann aus dem Schlüsseltyp, insbesondere sk, ableiten, dass es sich nicht um einen echten privaten Schlüssel handelt, sondern dass ein Sicherheitselement angesprochen werden muss
      Anschließend prüft es die Einstellung SecurityKeyProvider oder die Umgebungsvariable SSH_SK_PROVIDER, um herauszufinden, von wo die dynamische Library geladen werden soll, die die Kommunikation mit dem Sicherheitselement ermöglicht

  • Der Artikel scheint nur SSH zu behandeln, aber gibt es eine Möglichkeit, das Secure Enclave oder TPM meines Computers als FIDO2- oder U2F-Schlüssel zu verwenden?

    • Natürlich, und das sollte fast mit den Standardeinstellungen funktionieren
      Passkeys sind ebenfalls eine Form dieses Ansatzes, bei dem pro Website ein separater privater Schlüssel verwendet wird
  • Wenn man das sieht, wirkt es seltsam, dass Unterstützung für asymmetrische oder HMAC-API-Schlüssel, die an Hardware gebunden werden können, nicht verbreiteter ist
    Es ist erfreulich zu sehen, dass immer mehr Spezifikationen in diese Richtung gehen, etwa WebAuthn, DBSC (Device-Bound Session Credentials) und OAuth2 DPOP