Sauvegarde fiable, sécurisée et polyvalente pour U2F

J'aime vraiment le niveau de sécurité fourni par U2F, mais avec la sécurité, vous devez envisager un plan de récupération. Perdre l'accès à vos comptes les plus importants, si quelque chose se passe avec le jeton U2F principal, est un problème grave. Dans le même temps, je voudrais éviter d'utiliser une sauvegarde qui compromet la sécurité fournie par U2F.

yubikey

Méthodes de sauvegarde populaires


À ce jour, il a été recommandé de conserver un deuxième jeton U2F indépendant pour la sauvegarde; ce jeton doit être ajouté manuellement à chaque service et stocké dans un endroit "sûr". Une autre pratique courante consiste à utiliser la méthode non U2F comme sauvegarde (OTP, codes de récupération). Honnêtement, ces deux méthodes laissent beaucoup à désirer.

Jeton U2F indépendant


Cela signifie que chaque fois que je m'inscris sur un nouveau service, je dois ajouter mes deux jetons. Ce fait soulève un certain nombre de problèmes:

  • Un jeton de sauvegarde doit être assez facilement accessible. Malgré le fait que je ne le porterai pas avec moi sur un porte-clés, je devrais pouvoir y accéder rapidement, donc je peux à peine trouver quelque chose de mieux que de le garder à la maison. Dans quelle mesure il est sûr, même si un coffre-fort est utilisé, vous pouvez parler longtemps;
  • Lorsque je dois m'inscrire à un service lorsque je suis loin de chez moi, je ne peux pas ajouter de jeton de sauvegarde. Vous devez donc essayer de vous rappeler que vous devez l'ajouter plus tard, et jusqu'à ce que cela se produise, il n'y a pas de sauvegarde. Dans le pire des cas, je peux complètement l'oublier;
  • Quand je suis à la maison, mes deux jetons sont au même endroit. Cette méthode de sauvegarde est loin d'être idéale: les deux jetons peuvent être indisponibles en raison d'un incident (être détruits ou volés);
  • Le fait que le jeton de sauvegarde soit stocké à la maison est tout à fait évident. Si quelqu'un veut vraiment accéder à mon jeton, il sait déjà où le chercher;
  • Méthode non universelle: tous les services ne vous permettent pas d'ajouter plus d'une clé à votre compte.

À mon avis, cette «pratique exemplaire» n'est pas très fiable et plutôt contraignante. Regardons une autre pratique courante.

Méthode non U2F comme sauvegarde


OTP:

  • Il est préférable d'utiliser OTP comme sauvegarde que de l'utiliser comme méthode 2FA principale, mais le fait d'avoir OTP ouvre en quelque sorte un vecteur d'attaque supplémentaire;
  • Les téléphones tombent en panne, se perdent et sont volés, et si après leur perte il y a une chance qu'ils soient entre les mains d'étrangers, alors vous devez rappeler manuellement cette sauvegarde sur tous les comptes;
  • Je porte toujours un téléphone et un jeton U2F avec moi, donc encore une fois, une telle méthode de sauvegarde est loin d'être idéale: la probabilité de les perdre tous les deux à la fois est beaucoup plus élevée que si la sauvegarde était stockée séparément. Mais cet élément peut être légèrement compensé en utilisant, par exemple, Authy, qui stocke la sauvegarde chiffrée sur son serveur;
  • Méthode non universelle: malheureusement, il existe un nombre suffisant de services qui n'offrent que des applications personnalisées et ne prennent pas en charge TOTP standard.

Codes de récupération:

  • Les codes de récupération doivent être stockés dans un endroit sûr. Encore une fois, cet «endroit sûr» sera probablement ma maison, avec presque les mêmes problèmes qu'un jeton U2F distinct;
  • Encore une fois, une méthode non universelle: chaque service a sa propre approche de sauvegarde

Donc, pour résumer, toutes ces méthodes sont non universelles, lourdes et pas trop sûres.

La meilleure méthode de sauvegarde


Maintenant, après avoir suffisamment critiqué la situation actuelle, je dirai enfin ce que je veux vraiment. Je veux vraiment avoir deux jetons U2F: primaire et sauvegarde, mais ils doivent être configurés d'une certaine manière:

  • Lorsque j'enregistre le jeton principal sur n'importe quel appareil, le jeton de sauvegarde devient automatiquement opérationnel pour ce service;
  • Dès que j'utilise un jeton de sauvegarde sur un service, le jeton principal n'est pas valide pour ce service.

Avant de discuter de la faisabilité technique de cela au sein de U2F, j'expliquerai pourquoi c'est génial et comment je l'utilise.

Pourquoi c'est génial


Si nous regardons la critique du jeton de sauvegarde indépendant décrit ci-dessus, nous pouvons voir que tous les défauts de cette méthode sont éliminés:

  • Le jeton de sauvegarde ne devrait plus être facilement accessible. Des exemples extrêmes peuvent être: briquez un jeton à l'intérieur d'un mur de briques, ou enterrez un mètre et demi dans un jardin ou ailleurs. Sans blague, je suis tout à fait prêt à y aller;
  • Peu importe où je me trouve, si je m'inscris à un service, je n'ai rien à faire pour ajouter un jeton de sauvegarde à ce service. J'utilise juste mon jeton principal, et je suis en toute tranquillité d'esprit, sachant que j'ai une sauvegarde;
  • Pour les étrangers, il est complètement difficile de savoir où se trouve mon jeton de sauvegarde. Même en sachant qu'il existe, essayer de le trouver vous-même n'a guère de sens;
  • C'est assez sûr. Même si quelque chose de mal arrive à mon jeton principal, il est très peu probable que le même incident affecte le jeton de sauvegarde;
  • C'est universel. Cette méthode de sauvegarde fonctionnera sur tout service qui prend en charge U2F, indépendamment de ce que ce service prend en charge.

Et si quelque chose de grave se produit vraiment avec le jeton principal, je fais ce qui suit:

  • Je déterre / efface un jeton de sauvegarde;
  • Authentifiez-vous sur tous mes services avec U2F, annulant ainsi le jeton principal;
  • Je commande une nouvelle paire de jetons et, à la réception, j'ajoute un nouveau jeton principal sur tous les services et révoque l'ancien.

Du moins pour moi personnellement, cette stratégie est un grand compromis pour un haut niveau de sécurité et un fardeau de sauvegarde facile. Il est plus sûr et plus fiable que toute autre méthode.

Implémentation


Présentation du protocole U2F


Avant de parler d'implémentation, nous devons comprendre à un certain niveau comment fonctionne U2F. La plupart des fabricants l'implémentent comme suit (tous les éléments suivants ne sont pas présents dans la norme; certains éléments sont des détails d'implémentation, mais la plupart des implémentations existantes, pour autant que je sache, fonctionnent de cette façon):

device_secret programmé dans le jeton U2F, avec un counter 32 bits, qui ne peut être incrémenté. Lorsque nous enregistrons un jeton U2F sur un service, les événements suivants se produisent:

  • Le navigateur envoie l' AppID (en fait, le nom de domaine) au périphérique U2F;
  • L'appareil génère un nombre aléatoire ( nonce ), le combine avec lui avec l' AppID , le transmet à travers HMAC-SHA256 en utilisant device_secret comme clé, et le hachage résultant devient la clé privée pour ce service particulier: service_private_key ;
  • A partir de service_private_key , la clé publique service_public_key générée;
  • L'appareil prend à nouveau l' AppID , le combine avec service_private_key et le transmet à nouveau via le HMAC-SHA256 en utilisant device_secret comme clé. Le résultat ( MAC ), avec le nonce qui a été généré précédemment, devient key_handle ;
  • L'appareil renvoie key_handle et service_public_key au navigateur, et le navigateur passe au service, qui enregistre ces données pour de futures authentifications.

L'authentification suivante se déroule comme suit:

  • Le service génère un challenge (données générées aléatoirement) et l'envoie au navigateur avec key_handle (qui se compose de nonce et MAC ). Le navigateur transmet tout cela à l'appareil, ainsi que l' AppID (c'est-à-dire le nom de domaine);
  • L'appareil, ayant nonce et AppID , génère service_private_key de la même manière qu'il a été généré lors de l'inscription;
  • L'appareil génère un MAC de la même manière que lors de l'enregistrement, et en le comparant avec le MAC reçu du navigateur, il s'assure que nonce pas remplacé, et donc, service_private_key fiable;
  • Le périphérique incrémente le counter ;
  • L'appareil signe le challenge , l' AppID et le counter aide de service_private_key , et envoie la signature ( signature ) et le counter résultants counter navigateur, qui transfère ces données au service;
  • Le service vérifie la signature à l'aide de la service_public_key qu'il possède après l'enregistrement. De plus, la plupart des services vérifient que le counter plus grand que la valeur précédente (s'il ne s'agit pas de la première authentification). Le but de ce test est de rendre le clonage des appareils U2F inaccessible. Par conséquent, si la signature correspond et que le counter supérieur à la valeur précédente, l'authentification est considérée comme terminée avec succès et le service enregistre la nouvelle valeur du counter .

Décrivons maintenant les détails directement liés à la discussion.

Détails d'intérêt


La première est que le périphérique ne stocke pas service_private_key pour chaque service: à la place, il affiche service_private_key chaque fois en utilisant HMAC-SHA256. C'est très important pour nous: il est évident que si chaque appareil stockait des clés uniques séparément pour chaque service, alors seul cet appareil pourrait s'authentifier par la suite.

Soit dit en passant, ce n'est pas une exigence de U2F: U2F n'indique pas comment les clés doivent être stockées, et certaines premières implémentations de U2F ont en fait stocké les clés pour chaque service séparément. Cette approche présente l'inconvénient que le nombre de services pour lesquels l'appareil peut être utilisé est limité. La dérivation de service_private_key élimine cet inconvénient.

Et deuxièmement, l'appareil dispose d'un counter pour empêcher le clonage.

À première vue, il peut sembler que ce counter ne nous permet pas de mettre en œuvre la stratégie de sauvegarde discutée (du moins il m'a semblé quand j'ai essayé de trouver une solution), mais en fait, cela ne fait que nous aider! Je vais vous expliquer maintenant.

Idée principale


L'idée est la suivante: au stade de la production, programmez deux jetons de manière à ce qu'ils aient tous les deux le même device_secret , mais le jeton de sauvegarde a besoin d'une correction: au lieu d'utiliser le counter dans sa forme pure (comme le font les jetons ordinaires), il devrait ajouter une grosse constante pour counter . Par exemple, la moitié de la plage 32 bits, c'est-à-dire environ 2 000 000 000 , cela semble raisonnable: il est peu probable que j'épuise autant d'authentifications dans toute ma vie.

En fait, c'est tout. Simple et efficace.

Ayant deux jetons programmés de cette manière, je cache le jeton de sauvegarde dans un endroit vraiment difficile à atteindre et ne le touche jamais. Si quelque chose de terrible se produit et que je perds l'accès au jeton principal, j'arrive toujours au jeton de sauvegarde et je peux l'utiliser immédiatement sur tous les services où j'ai enregistré le jeton principal, car La sauvegarde a le même device_secret , et son counter démarre avec un très grand nombre, que je n'aurai pas pour le reste de ma vie.

Aussi, j'attire l'attention sur le fait que je ne propose pas de faire des jetons clonés . Deux jetons, bien qu'ils aient le même device_secret , ont des compteurs différents, et après la programmation de device_secret il ne devrait y avoir aucun moyen de le récupérer à partir du périphérique ou de créer un clone d'une autre manière.

Une note sur Counter


Un lecteur attentif peut remarquer qu'il existe le problème de sécurité suivant: que se passe-t-il si un attaquant accède au jeton principal et initie en quelque sorte 2 000 000 000 d'authentifications? Il accède ensuite au service même après que le jeton de sauvegarde a été utilisé sur ce service.

Heureusement, ce problème a une solution simple. Dans tous les cas, le compteur matériel doit être implémenté dans le matériel (vraisemblablement sur certains processeurs cryptographiques), et pour une implémentation sûre, ce compteur matériel doit avoir une plage inférieure à 32 bits. Par exemple, sur l' ATECC508A, les compteurs ne peuvent compter que jusqu'à 2097151, donc en définissant la constante ajoutée au compteur sur une valeur supérieure à la valeur maximale du compteur, nous pouvons être sûrs que le jeton principal ne pourra jamais compter sur le compteur dans le jeton de sauvegarde.

Pour clarifier: disons que notre jeton U2F utilise ATECC508A et désignons le compteur à l'intérieur de l'ATECC508A comme hw_counter . Ensuite:

  • Dans le jeton principal, nous utilisons pour les calculs: hw_counter ;
  • Dans le jeton de sauvegarde, nous utilisons pour les calculs: hw_counter + 2000000000 .

Veuillez noter que nous ne modifions pas le vrai hw_counter à l'intérieur du processeur cryptographique; il comptera toujours de 0 à 2097151. Au lieu de cela, chaque fois que nous avons besoin d'obtenir la valeur du compteur, nous lisons hw_counter de ATECC508A, puis nous ajoutons notre constante et la renvoyons (pour d'autres calculs pour U2F).

Ainsi, la plage de valeurs de compteur dans le jeton principal sera [0, 2097151], tandis que la plage de valeurs de compteur dans le jeton de sauvegarde sera [2000000000, 2002097151]. Le fait que ces plages ne se chevauchent pas garantit l'annulation du jeton principal lors de l'utilisation de la sauvegarde (si le service utilise un counter ; les principaux services que j'ai vérifiés l'utilisent).

Mise en œuvre réelle


Aucun des fabricants de jetons U2F que je connais ne prend en charge la personnalisation requise aujourd'hui. Mais heureusement, il existe une implémentation open-source du token U2F: SoloKeys .

J'ai écrit mon article original (en anglais) il y a un an, et cette partie est un peu datée: alors SoloKeys était au stade du prototypage, et j'ai utilisé l'itération précédente du projet: u2f-zero . Par conséquent, je ne traduirai pas cette partie maintenant, car la seule façon d'obtenir un appareil u2f-zero est de le souder vous-même, et il n'est guère conseillé de le faire (bien qu'il y ait des instructions sur le github).

Néanmoins, tous les détails de la modification nécessaire de u2f-zero sont donnés dans l' article d'origine .

Lorsque mes mains atteindront les solokeys, j'écrirai des instructions pour sa modification.

D'une manière ou d'une autre, c'est le seul moyen que je connaisse aujourd'hui pour obtenir un jeton U2F fonctionnel avec une sauvegarde fiable. La vérification de plusieurs services (au moins google et github) a montré que cela fonctionne: en enregistrant le jeton principal sur le service, nous pouvons également utiliser la sauvegarde, et après la première utilisation de la sauvegarde, le jeton principal cesse de fonctionner. Awwwwwww. <3

Avertissement


Malgré le fait que cette stratégie de sauvegarde soit cool, je ne suis pas sûr de sa mise en œuvre spécifique via u2f-zero ou solokey. Ce chemin est le seul moyen d'obtenir ce que vous voulez, alors je suis allé de cette façon; mais en supposant que l'attaquant obtienne un accès physique à l'appareil U2F, je ne suis pas sûr que le piratage de l'appareil (c'est-à-dire en obtenant device_secret ) sera aussi difficile que dans le cas de Yubikey ou d'autres grands fabricants. Les auteurs de solokey affirment que «le niveau de sécurité est le même que dans une clé de voiture moderne», mais je n'ai effectué aucun examen pour le confirmer.

Cependant, pour être honnête, je ne suis pas vraiment inquiet à ce sujet. Si un attaquant vole simplement un jeton sans avoir l'intention de le retourner, la complexité de le casser n'a pas d'importance, car un attaquant peut simplement utiliser ce jeton pour accéder à un compte et, par exemple, simplement révoquer ce jeton et en ajouter un autre. Cependant, pour cela, je dois également avoir d'autres problèmes de sécurité graves. Le jeton U2F n'est que le deuxième facteur.

Ainsi, le seul scénario dans lequel solokey peut être moins sécurisé qu'autre chose est lorsqu'un attaquant essaie d'accéder à l'appareil pendant une courte période, d'obtenir device_secret de lui et de me renvoyer l'appareil de manière invisible. Pour ce faire, il doit lire le contenu du microcontrôleur flash (ou RAM au bon moment), et ce n'est pas très banal.

Compte tenu de tous les facteurs, je pense que pour moi personnellement, avoir une sauvegarde fiable est beaucoup plus important que d'avoir une implémentation matérielle ultra-sécurisée d'un appareil U2F. La probabilité de problèmes avec une implémentation aussi sûre et l'absence d'une bonne sauvegarde est plus élevée que la probabilité de problèmes avec u2f-zero (solokey) et la sauvegarde.

Conclusion


La stratégie de sauvegarde envisagée surpasse les alternatives dans toutes les dimensions: elle est universelle, plus sûre et plus fiable que toutes les autres méthodes.

Je serai heureux si au moins l'un des principaux fabricants implémente cela dans leurs produits, mais il n'y a pas encore de certitude. Un gars du support de Yubico, James A., m'a même dit que pour implémenter la sauvegarde comme j'avais besoin, ce n'était pas possible avec la façon dont U2F est conçu, et après avoir défini les détails de l'implémentation, il a juste cessé de répondre.

Heureusement, ce n'était pas aussi impossible que le croit Yubico.



Mon article original en anglais: Reliable, Secure and Universal Backup for U2F Token . Parce que l'auteur de l'article original est moi-même, puis, avec votre permission, je n'ai pas mis cet article dans la catégorie «traduction» .

Source: https://habr.com/ru/post/fr474300/


All Articles