1 points par GN⁺ 4 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Un jeton de sécurité signe à l’intérieur de l’appareil sans jamais exporter la clé privée, et exige une action physique de l’utilisateur, ce qui rend difficile pour un attaquant distant de produire des signatures arbitraires
  • Il peut servir à l’authentification SSH, à l’U2F, à la connexion locale sans mot de passe, à sudo et à la signature des commits git, et les dispositifs de sécurité intégrés des ordinateurs portables et smartphones récents peuvent remplacer une YubiKey
  • Le fichier de « clé privée » créé avec ssh-keygen -t ed25519-sk n’est pas la vraie clé privée, mais un handle qui pointe vers la clé stockée dans le jeton ; avec le même jeton, on peut générer le même fichier de clé SSH sur un autre ordinateur
  • Sur MacBook, il a été possible de configurer le secure element comme clé SSH pour activer une connexion SSH via Touch ID, et pour la signature des commits git il a fallu utiliser ssh-agent et une configuration user.signingKey au format key:: plutôt qu’un chemin de fichier
  • Les jetons de sécurité ne permettent pas de récupérer la clé privée en cas de perte et posent un risque d’usage lié à l’habitude de toucher l’appareil à répétition ; sur les PC portables Windows, Windows Hello pouvait confirmer l’usage d’une clé SSH par reconnaissance faciale, empreinte ou PIN

Avantages et limites des jetons de sécurité

  • Une architecture clé pour bloquer les attaques à distance

    • Un jeton de sécurité conserve la paire clé privée/clé publique dans l’appareil ; la clé publique s’exporte facilement, mais la clé privée ne sort jamais de l’appareil
    • Quand on envoie à l’appareil le paquet de données à signer, la signature est produite à l’intérieur avec la clé privée, et cela demande en général une action physique de l’utilisateur, comme appuyer sur un bouton tactile clignotant
    • Même si un attaquant distant prend le contrôle de l’ordinateur, le jeton de sécurité ne produira pas de signature arbitraire tant que l’utilisateur n’agit pas physiquement dans le monde réel ; cela paraît donc préférable à une approche où l’on laisse une paire complète de clés SSH privées/publiques sous forme de fichiers dans ~/.ssh
    • Il existe aussi des options pour ceux qui veulent un firmware FOSS, comme SoloKeys et Nitrokeys
    • Les jetons de sécurité plus haut de gamme ajoutent parfois des fonctions biométriques, comme un lecteur d’empreintes intégré, mais le point essentiel reste que la clé privée ne quitte jamais l’appareil
  • Les risques liés à l’usage

    • Si l’utilisateur s’habitue à appuyer chaque fois que le jeton de sécurité clignote, il peut aussi répondre machinalement à une requête malveillante
    • Lors de suites de signatures successives, quand il faut toucher le jeton de façon répétée, il peut devenir difficile de remarquer qu’une demande supplémentaire clignote
    • Apple et Microsoft utilisent sur les applis d’authentification mobile un système où un code numérique aléatoire est affiché à chaque requête d’accès et doit être saisi par l’utilisateur, mais c’est plus contraignant et cela réduit l’avantage ergonomique des jetons de sécurité par rapport à des applis comme Authy ou Google Authenticator utilisant TOTP
  • Perte et sauvegarde

    • Si l’on perd un jeton de sécurité, la clé privée correspondante disparaît définitivement et il n’existe aucun moyen de la sauvegarder
    • Pour éviter de se retrouver bloqué sur plusieurs comptes, mieux vaut acheter au moins deux jetons de sécurité et les enregistrer sur les mêmes services
    • Une alternative consiste à utiliser un système de sauvegarde et de restauration comme BIP 39, qui convertit la clé privée en une liste de mots lisibles par un humain
    • Si la clé privée pouvait sortir de la Secure Enclave, cela ouvrirait aussi la voie à des attaques de phishing visant à pousser l’utilisateur à noter cette liste de mots au mauvais endroit
    • Si la possibilité de perdre tous ses jetons de sécurité est une vraie inquiétude, la liste de mots BIP 39 peut devenir le dernier recours pour récupérer l’accès au système

Utiliser un jeton de sécurité avec SSH et git

  • Mettre la clé privée SSH dans un jeton de sécurité

    • En temps normal, l’exécution de ssh-keygen crée une paire de fichiers contenant la clé privée complète
    • Pour placer la clé privée dans un jeton de sécurité, il faut installer libfido2 en suivant les instructions FIDO/U2F de Yubico, puis exécuter ssh-keygen -t ed25519-sk avec le jeton branché
    • Là aussi, une paire de fichiers est créée, mais le fichier de « clé privée » n’est pas la vraie clé privée : c’est un handle qui pointe vers la clé privée stockée dans le jeton
    • Si l’on relance ssh-keygen -t ed25519-sk avec le même jeton de sécurité, on peut régénérer la même paire clé privée/clé publique sur n’importe quel ordinateur ; l’accès SSH se déplace donc avec le jeton de sécurité plutôt qu’avec un fichier précis sur une machine donnée
  • Authentification git et signature des commits

    • Environ 90 % des situations où il faut toucher le jeton de sécurité viennent de l’usage de git
    • Les forges git implémentent l’authentification SSH pour les opérations push et pull, et il suffit d’y téléverser le fichier id_ed25519_sk.pub généré plus haut pour autoriser cette paire de clés liée au jeton de sécurité
    • git prend aussi en charge les clés SSH pour la signature des commits ; en suivant la documentation GitHub Configurer votre clé de signature avec une clé SSH, puis en exécutant git config --global commit.gpgsign true, tous les commits sont signés automatiquement
    • Pour qu’une forge git reconnaisse les commits comme étant signés par vous, il faut téléverser à nouveau la clé publique, généralement dans un champ distinct de celui utilisé pour l’authentification SSH
  • Les inconvénients de la signature des commits

    • Lors d’un rebase d’une longue série de commits, il faut tous les signer à nouveau
    • Sur une YubiKey équipée d’un lecteur d’empreintes, le taux d’échec de reconnaissance était trop élevé pour signer des dizaines de commits d’affilée, au point d’abandonner cet usage
    • Le wrapper centré sur “rebase/amend” de git, jujutsu, propose une méthode pour signer les commits uniquement au moment du push
  • Connexion locale Linux et sudo

Utiliser le secure element du MacBook comme clé SSH

  • Laisser un jeton de sécurité branché en permanence sur un port USB-C revient à laisser dépasser un petit levier qui peut endommager à la fois le port et le jeton en cas de chute ou de choc
  • Sur un MacBook Air M1 de 2020, le secure element intégré a été configuré comme clé SSH en suivant les instructions d’Arian van Putten
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""
  • Cette commande crée une paire de fichiers clé privée/clé publique id_ecdsa_sk_rk, ensuite déplacée dans le répertoire ~/.ssh
  • Là encore, le fichier de clé privée n’est pas la vraie clé privée mais un handle vers la clé stockée dans l’appareil, ce qui lui donne une forme que l’on peut coller publiquement
  • Pour ajouter la clé publique comme authorized key sur un serveur de homelab, il faut exécuter :
ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname>
  • Puis ajouter la configuration suivante dans ~/.ssh/config
Host *
  IdentityFile ~/.ssh/id_ecdsa_sk_rk
  SecurityKeyProvider=/usr/lib/ssh-keychain.dylib
  • Quand on lance ssh <server nickname>, macOS affiche automatiquement une demande d’empreinte avant la connexion, puis l’authentification SSH se déroule normalement

Signer des commits git avec le secure element du MacBook

  • Même après avoir défini git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk et mis à jour le fichier .ssh/allowed_signers, la signature des commits git ne fonctionne pas immédiatement
  • git échoue à signer les commits et affiche une erreur du type device not found?
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
  • La solution consiste à utiliser ssh-agent au lieu de pointer directement vers les fichiers du répertoire ~/.ssh
  • En suivant le tutoriel ci-dessus, on enregistre la paire de clés dans ssh-agent avec la commande suivante
ssh-add -K -S /usr/lib/ssh-keychain.dylib
  • Ensuite, dans user.signingKey, il faut mettre non pas un chemin de fichier mais la clé elle-même, précédée de key::, en reprenant le contenu de ~/.ssh/id_ecdsa_sk_rk.pub dans ~/.gitconfig
[user]
	name = Andrew Helwer
	signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"
  • Après ce réglage, il a été possible de signer des fichiers avec la clé stockée dans le secure element du MacBook puis de les pousser sur un site GitLab Pages

Résultats sous Windows et Linux

  • Un essai rapide a aussi été réalisé sur l’ordinateur portable Windows fourni par l’entreprise
winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk
  • Cette commande a elle aussi créé une paire de fichiers clé privée/clé publique, et lors d’une connexion SSH elle acceptait, via le flux standard de connexion Windows Hello, la reconnaissance faciale, l’empreinte ou le PIN
  • Sous Linux, il n’a pas été possible de faire une démonstration, faute d’accès à un ordinateur portable dont le secure element demandait une vérification comparable de la présence réelle de l’utilisateur

1 commentaires

 
GN⁺ 4 시간 전
Avis sur Lobste.rs
  • Excellent article, et le simple fait de montrer que c’est possible est déjà très utile
    Personnellement, je n’ai pas trouvé la bonne version de bibliothèque pour faire fonctionner ça, mais j’ai découvert que 1Password 8 stocke les clés SSH de façon sécurisée et que son agent prend en charge le déverrouillage de la clé par authentification biométrique
    Du coup, je peux maintenant faire du git et me connecter à des hôtes SSH juste en posant mon doigt
    Guide : https://developer.1password.com/docs/ssh/get-started/

  • Ça a l’air réservé à Mac

    • Au travail, je peux utiliser un portable Windows récent, donc j’ai configuré OpenSSH pour qu’il s’intègre à Windows Hello comme suit
      winget install Microsoft.OpenSSH.preview  
      ssh-keygen -t ecdsa-sk  
      
      Ensuite, ça s’est comporté comme avant, sauf qu’à chaque connexion SSH avec la clé, je passais par le flux standard Windows Hello et pouvais utiliser soit le lecteur d’empreintes, soit la reconnaissance faciale, soit le PIN
      Je n’ai pas eu l’occasion d’essayer un système Linux avec ce type d’élément sécurisé, et sur ma station de travail Linux, j’ai un TPM V1, mais je ne vois pas vraiment comment garantir que les opérations de signature ne s’exécutent qu’après vérification de la présence réelle de l’utilisateur
      Quelqu’un avec un portable Linux comme un Framework pourrait peut-être tenter l’expérience. Peut-être que ça pourrait même fonctionner sur Asahi
    • Oui, en gros. Je ne sais pas s’il existe une couche d’émulation TPM2 FIDO sous Linux ou Windows
  • Donc, qu’y a-t-il exactement dans le fichier de clé privée fourni ?

    • @wrs a répondu avant moi, mais la partie ssh:, c’est-à-dire l’application, correspond à l’origin d’une passkey et sert à créer des clés résidentes par hôte ou par domaine
      Par exemple, je m’en sers pour séparer les clés par usage même sur la même Yubikey physique
      flags indique comment le matériel doit traiter la clé [1]. L’agent peut aussi ajouter ses propres restrictions
      Techniquement, on peut également stocker d’autres blobs ou extensions dans une clé FIDO ; dans mon précédent poste, je m’en suis servi pour transmettre, avec l’authentification, des identifiants auxiliaires comme une clé publique X.509. C’est assez élégant comme approche
      [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  
      
    • D’après Claude, et après vérification avec openssh_key_parser, la structure est la suivante
      L’enveloppe externe contient la valeur magique openssh-key-v1\0, cipher=none, kdf=none, donc ce n’est pas du texte chiffré
      Le blob de clé publique de 74 octets contient le type de clé sk-ssh-ed25519@openssh.com, un point Ed25519 de 32 octets fdcce889…03e7852b, et l’application ssh:, ce qui sépare les credentials FIDO entre SSH et WebAuthn via un espace de noms distinct
      La section privée fait 248 octets et, avec cipher=none, elle est en clair. On y trouve checkint1 == checkint2 == 0x46744267 comme valeur aléatoire, le type de clé et la clé publique répétés, l’application ssh:, et flags: 0x01
      Ce drapeau signifie USER_PRESENCE_REQUIRED, donc un toucher est requis, mais pas de PIN ni de vérification utilisateur, et il s’agit d’une clé non résidente
      key_handle est un ID de credential opaque de 128 octets transmis à authenticatorGetAssertion, que l’appareil déplie en interne pour retrouver la graine Ed25519
      Il y a aussi un champ reserved vide, le commentaire ahelwer@ah-mbair.local, et le padding 01 02 03
    • Si on le passe dans un décodeur base64, on obtient ceci

      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 !{"8N ai*W�y53 �������ahelwer@ah-mbair.local
      On y voit la version standard de clé v1, le type de clé sk-ssh-ed25519@openssh.com, répété pour une raison quelconque, ainsi qu’un nom de clé lisible par un humain, ahelwer@ah-mbair.local
      Le reste semble être des drapeaux OpenSSH, par exemple pour indiquer si un PIN ou une preuve de présence utilisateur sont requis, ainsi qu’un handle GUID qu’OpenSSH peut transmettre à l’API FIDO/U2F avec le challenge
      OpenSSH peut déduire, à partir du type de clé, en particulier sk, qu’il ne s’agit pas d’une vraie clé privée mais qu’il doit appeler l’élément sécurisé
      Ensuite, il regarde la configuration SecurityKeyProvider ou la variable d’environnement SSH_SK_PROVIDER pour savoir d’où charger la bibliothèque dynamique qui permet de communiquer avec l’élément sécurisé

  • Cet article semble ne parler que de SSH, mais y a-t-il un moyen d’utiliser le Secure Enclave ou le TPM de mon ordinateur comme clé FIDO2 ou U2F ?

    • Bien sûr, et ça devrait fonctionner presque avec la configuration par défaut
      Une passkey est aussi une forme de cette approche, avec une clé privée distincte pour chaque site web
  • En voyant ça, je trouve étrange qu’il ne soit pas plus courant de prendre en charge des clés API asymétriques ou HMAC pouvant être liées au matériel
    C’est encourageant de voir se multiplier des spécifications comme WebAuthn, DBSC (Device-Bound Session Credentials) et OAuth2 DPOP, qui poussent davantage dans cette direction