< Back
Passkey sur Android : les petits détails qui mènent à de gros problèmes

Tags:

Risk and threat evaluation
14 November 2024

Passkey sur Android : les petits détails qui mènent à de gros problèmes

Introduction 

Passkey est une technologie créée et maintenue par l’alliance FIDO, fondée par de nombreuses entreprises bien connues comme Google, Microsoft ou Apple. L’objectif de cette technologie, qui est une implémentation des standards FIDO2, est de remplacer et supprimer le besoin de mots de passe.

La technologie est, au moment de la rédaction, en constante évolution, ce qui rend son développement et sa maintenance plus difficiles.

Il y a quelques semaines, j’ai décidé de développer une application Android qui utiliserait cette technologie comme mécanisme d’authentification pour comprendre comment elle fonctionne. Cela n’a pas été aussi facile que je le pensais car de nombreuses exigences pour que l’implémentation Android fonctionne ne sont pas regroupées en un seul endroit et sont dispersées sur le web.

L’objectif de cet article est de résoudre ce problème et de mettre en évidence les pièges courants dans lesquels vous pourriez tomber lors du développement d’une application Android utilisant les passkeys.

La plupart des exigences doivent être remplies côté serveur, rien à voir avec le code de votre application en tant que tel. Nous commencerons par celles-ci afin que vous puissiez commencer à tester vos communications de passkeys dans de bonnes conditions.

Un fichier bien connu

Pour que l’implémentation des passkeys sur Android accepte de communiquer avec votre serveur, Google, qui dirige Android, doit pouvoir vérifier le fichier “/.well-known/assetlinks.json” sur votre serveur. Ce fichier doit contenir des informations sur les applications Android qui ont la permission de communiquer avec le serveur. Google a fourni un outil pour aider les développeurs à tester leur fichier.

Toutes les informations et contraintes requises peuvent être trouvées ici. D’après cette documentation, nous pouvons apprendre que les contraintes suivantes doivent être respectées pour le fichier (citées directement) :

  • Il doit être publiquement accessible et non derrière un VPN.
  • Il doit être servi avec le Content-type: application/json.
  • Il doit être accessible via HTTPS.
  • Il doit être servi directement avec une réponse HTTP 200 response (pas de redirection HTTP 300).
  • Assurez-vous qu’aucun fichier robots.txt ne l’empêche :
    • User-agent: *
    • Allow: /.well-known/

Un domaine enregistré

Avez-vous remarqué que j’ai dit que “Google doit vérifier” et non “Android doit vérifier” ? C’est parce qu’Android demandera à un serveur Google si votre serveur est “légitime” et ne le vérifiera pas lui-même. Donc, si votre serveur n’est pas accessible depuis Internet, l’API  passkey d’Android refusera de communiquer et vous donnera une erreur cryptique.

cryptic error

De plus, à ma connaissance, utiliser simplement une adresse IP ne fonctionnera pas, votre serveur doit être derrière un nom de domaine pour être vérifié par le serveur Google.

Une origine qui n'en est pas une

Lors du processus d’authentification, la requête contenant la réponse au défi, une chaîne aléatoire qui a été signée en utilisant la clé privée de l’entrée de passkey sélectionnée, contient également un champ “Origin” dans le paramètre clientData. Jusqu’ici, pas de problème… jusqu’à ce que vous lisiez le contenu de l’Origin, qui est une signature du certificat utilisé pour signer l’APK, et non une origine au sens traditionnel HTTP. Par exemple, si nous prenons le clientDataJson du gestionnaire d’identifiants, nous pouvons observer ceci :

credential-manager

 Décodage du clientDataJSON avec CyberChef

Figure 1. Décodage du clientDataJSON avec CyberChef

Cela peut être une très mauvaise nouvelle si, comme moi, vous avez utilisé une bibliothèque comme passport-fido2-webauthn pour vous aider à gérer les passkeys côté serveur. C’est un problème parce que la bibliothèque ne supporte pas ces origines, qui ont été générées par l’API des passkeys d’Android, dans le clientdata des requêtes. Cela signifie que votre serveur refusera toutes les requêtes d’authentification provenant de votre application Android.

Pour contourner ce problème, vous devrez trouver un moyen d’enregistrer la signature du certificat dans vos configurations afin que le serveur l’accepte. Cela peut signifier que vous devrez patcher la bibliothèque vous-même si elle ne supporte pas les origines d’Android. Pour ceux d’entre vous qui ont décidé d’utiliser la même bibliothèque que moi, j’ai fait une PR pour résoudre le problème.

La dernière pièce du puzzle

C’est la seule partie de cet article qui concerne le code de l’application Android elle-même. Pour utiliser les passkeys avec l’API d’Android, il y a deux fonctions principales à utiliser avec des arguments spécifiques :

  • createCredentialAsync(): Créer une paire de clés passkey et signer un défi
  • getCredentialAsync(): Utiliser une paire de clés passkey existante pour signer un défi

Pour utiliser ces fonctions, un objet CredentialManager est nécessaire, il peut être obtenu en en créant un en utilisant le contexte de l’application : CredentialManager.create(getApplicationContext())

C’est assez simple si l’on ignore un de leurs paramètres : request

CredentialManager

Pour créer une nouvelle paire de clés passkey, un JSON respectant un format spécifique doit être construit. Les champs requis et le format du JSON peuvent être trouvés ici.

Pour référence, voici un exemple de code que j’ai réalisé il y a quelques jours :

Generating a Passkey key pair

Figure 2. Génération d'une paire de clés Passkey

The function used to build the options

Figure 3. La function utilisée pour contruire les options

Conclusion

Passkey est une excellente technologie qui évolue rapidement. Cela a un prix : tous les prérequis pour que les passkeys fonctionnent correctement dans une application Android ne sont pas bien documentés. Cet article visait à mettre en lumière ces points afin que vous puissiez commencer votre aventure avec les passkeys de manière plus sereine.

Auteur

Alexis Pain