https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-a-google-authenticator-from-a-landline-with-vonage/Social_Google-Authenticator_1200x627.png

Créer un "Google Authenticator" à partir d'une ligne fixe avec Vonage

Publié le May 7, 2021

Temps de lecture : 23 minutes

Nous adorons l'authentification à deux facteurs (2FA) : l'utilisation d'un mot de passe mémorisé et d'un code d'accès à usage unique généré par votre téléphone portable rend la connexion tellement plus sûre. Le problème d'une bonne sécurité, cependant, c'est qu'il est très facile de s'enfermer à l'extérieur.

Imaginez que vous êtes loin de chez vous, en vacances ou en voyage d'affaires dans une ville lointaine. Vous pouvez utiliser l'ordinateur partagé dans le hall de l'hôtel sans avoir peur des enregistreurs de frappe. Les pirates peuvent obtenir votre mot de passe, mais ils ne peuvent toujours pas accéder à vos données sans le téléphone dans votre main!

An example image of the authenticator

Mais que se passe-t-il si vous n'avez pas votre téléphone portable ? S'il est perdu, endommagé ou volé ? Eh bien, vous voudrez appeler votre assureur pour commencer... mais les coordonnées sont sur votre téléphone et dans votre email comme sauvegarde... et vous ne pouvez pas accéder à votre email sans votre téléphone puisque vous utilisez le 2FA ! 😱

Et si vous pouviez accéder à votre code d'accès 2FA en tant que service à distance ? Vous pourriez composer un numéro, saisir votre code PIN et vous faire lire les chiffres.

Contexte technologique

Bien que les premières mises en œuvre aient été propriétaires, il existe une norme ouverte de l'Initiative for Open Authentication (OATH) pour les mots de passe à usage unique basés sur le temps (TOTP), spécifiée dans le document RFC 6238. Cette norme prend un secret pré-partagé et le nombre de ticks de 30 secondes depuis 1970-01-01 00:00:00 UTC, calcule un hachage cryptographique et le transforme en un nombre à six chiffres qui ne peut être prédit sans connaître le secret.

Ce qui rend l'utilisation pratique, cependant, c'est un schéma URI défini par Google. Il se présente comme suit : otpauth://totp/Example:totp@example.com?secret=KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD&issuer=Example

Le plus souvent, ces URI sont codés sous la forme d'un code QR, comme celui-ci :

QR Code example for authentication.

Conditions préalables

Vous aurez besoin de quelques éléments pour cet exemple :

  • Google Authenticator (Android/iOSou toute autre application OATH TOTP similaire)

  • Un service prenant en charge le 2FA (tel qu'un Compte Google)

  • Un ngrok Account

  • A compte Heroku Account

  • ngrok installé localement (j'ai utilisé la version 2.3.35)

  • node.js installé localement (j'ai utilisé la version 12.6.1)

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

Applications

Nous allons utiliser node.js pour cet exemple parce qu'il est très facile d'exécuter un simple service web. Il y a aussi une implémentation assez sympa de la logique de mot de passe à usage unique dont nous avons besoin : otplib.

Tout d'abord, nous devons installer les librairies nécessaires, ce que nous faisons avec npm.

npm install express body-parser otplib

Placez maintenant le code suivant dans un fichier appelé totp.js. Nous commencerons par le code PIN d'accès et le secret partagé, qui est le même que celui du code QR ci-dessus, et nous ajouterons otplib.

const totp = require('otplib');

// Hardcoded secrets
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
const pin = '1234';

Nous allons construire un simple node.js Express utilisant l'API Voice de Vonage pour répondre à l'appel et renvoyer un Nexmo Call Control Object (NCCO) indiquant à l'API d'utiliser la synthèse vocale pour prononcer une phrase et attendre la saisie de l'utilisateur via le clavier du téléphone. Il s'agit d'un système de réponse vocale interactive (IVR) très simple, mais nous n'allons pas nous étendre sur le fonctionnement de l'API Voice ici. Si vous souhaitez comprendre plus en détail ce que fait ce code, jetez un coup d'œil à ce tutoriel.

const app = require('express')()
const bodyParser = require('body-parser')

app.use(bodyParser.json())

const onInboundCall = (request, response) => {
  const ncco = [
    {
      action: 'talk',
      text: 'Please enter your PIN, followed by a hash.'
    },
    {
      action: 'input',
      eventUrl: [`${request.protocol}://${request.get('host')}/webhooks/passcode`]
    }
  ]

  response.json(ncco)
}

Nous passons maintenant à la partie critique : nous vérifions le code PIN saisi par l'utilisateur. S'il est correct, nous obtiendrons le code d'accès actuel et le lirons à l'utilisateur.

const onInput = (request, response) => {
  const dtmf = request.body.dtmf;
  if (dtmf === pin) {
    const token = totp.authenticator.generate(secret);
    const slow = token.split('').join('. ');

    const ncco = [{
      action: 'talk',
      text: `Passcode is ${slow}. Repeat. ${slow}.`
    }]

    response.json(ncco)
  } else {
    const ncco = [{
      action: 'talk',
      text: `Incorrect PIN. Goodbye.`
    }]

    response.json(ncco)
  }
}

Enfin, nous connectons les fonctions que nous venons de définir aux méthodes/chemins HTTP et démarrons l'application en écoutant sur port 3000.

const PORT = 3000

app
  .get('/webhooks/answer', onInboundCall)
  .post('/webhooks/passcode', onInput)

app.listen(PORT)

Voilà, c'est fait ! Vous pouvez maintenant l'exécuter avec node totp.js et le tester en allant sur http://localhost:3000/webhooks/answer dans votre navigateur - il retournera l'objet JSON de la fonction onInboundCall que nous venons de définir !

Déploiement local avec ngrok

C'est bien que quelque chose fonctionne, mais cela ne sert pas à grand-chose si nous ne pouvons y accéder que sur notre machine locale !

Les ngrok est un excellent moyen de mettre en place un transitaire dynamique pour rendre notre petit service disponible sur Internet. Il suffit de s'inscrire sur le site web - un compte gratuit suffit - et de lancer sur le site web - un Account gratuit est tout ce dont vous avez besoin - et ensuite exécutez :

ngrok authtoken

Cela sauvegardera les informations d'identification de votre Account localement, et vous pourrez ensuite configurer la redirection de HTTP vers le port 3000 (celui que nous avons utilisé ci-dessus) en exécutant :

ngrok http 3000

An image example of Ngrok running

Notez les URIs qu'il affiche car ils seront spécifiques à votre service et changeront à chaque fois que ngrok s'exécutera.

A nouveau, nous pouvons tester ceci avec notre navigateur en allant sur : https://bd934ed5.ngrok.io/webhooks/answer

Note : Vous devez utiliser l'URI fourni par ngrok.

ngrok nous offre également le HTTPS gratuit, de sorte que notre connexion sera sécurisée - c'est vraiment génial !

Configuration des API de Vonage

Il ne fait toujours pas rien rien du tout. C'est ici que ça devient intéressant.

Tout d'abord, nous devons créer une nouvelle application Voice API. Allez dans l'onglet "Vos applications" du tableau de bord des tableau de bord API de Vonage et cliquez sur le gros bouton "Create a new application" :

An example of the Vonage Dashboard

Saisissez un nom tel que "TOTP Passcode Example", et générez une paire de clés pour qu'il puisse avoir accès à l'API :

An example of generating a keypair to have API access

Activez ensuite la fonction "Voice" et définissez les URI d'événement (https://bd934ed5.ngrok.io/webhooks/passcode) et de réponse (https://bd934ed5.ngrok.io/webhooks/answer) en fonction des URI de ngrok que vous avez notés ci-dessus. Veillez à utiliser vos propres URI de ngrok. Notez que l'URI d'événement utilise HTTP POST, vous devrez donc le sélectionner dans la liste déroulante :

Choosing the capabilities and setting webhoosk for your Vonage Application

Si vous préférez utiliser un CLI, vous pouvez créer une application comme celle-ci.

Installez le CLI de Vonage globalement avec cette commande :

npm install @vonage/cli -g

Ensuite, configurez le CLI avec votre clé et votre secret API Vonage. Vous pouvez trouver ces informations dans le tableau de bord du développeur.

vonage config:set --apiKey=VONAGE_API_KEY --apiSecret=VONAGE_API_SECRET

Créez un nouveau répertoire pour votre projet et placez-y un CD :

mkdir my_project
CD my_project

Maintenant, utilisez le CLI pour créer une application Vonage.

vonage apps:create ✔ Application Name … theoretical_felidae ✔ Select App Capabilities › Voice ✔ Create voice webhooks? … yes ✔ Answer Webhook - URL … https://bd934ed5.ngrok.io/webhooks/answer ✔ Answer Webhook - Method › GET ✔ Event Webhook - URL … https://bd934ed5.ngrok.io/webhooks/passcode ✔ Event Webhook - Method › POST ✔ Allow use of data for AI training? Read data collection disclosure - https://help.nexmo.com/hc/en-us/articles/4401914566036 … yes

Pour pouvoir composer ce service, nous avons besoin d'un numéro orienté vers l'extérieur. Créez-en un en utilisant "Numbers" -> "Acheter des Numbers" dans le tableau de bord :

Screenshot showing example of buying a number in Vonage Dashboard

Là encore, pour les amateurs de CLI, il est possible de rechercher d'abord les numéros compatibles avec la voix (par exemple, aux États-Unis) :

vonage numbers:search US

Ensuite, achetez l'un des produits de la liste :

vonage numbers:buy [NUMBER] [COUNTRYCODE]

Enfin, nous devons lier ce numéro à l'application. Si vous allez dans "Mes Applications" dans le tableau de bord et que vous cliquez sur votre application TOTP, vous devriez voir une ligne en bas pour votre numéro et un bouton "Lier" sous "Gérer" :

Screenshot showing how to link a number to your application

Cliquez sur "Lien" et confirmez si nécessaire :

Screenshot showing confirmation of linking number to application

N'ayez crainte, armée CLI, il y a une commande pour cela aussi :

vonage apps:link APPLICATION_ID --number=YOUR_VONAGE_NUMBER

Il existe également des commandes pratiques si vous ne vous souvenez pas du numéro de téléphone (vonage numbers) ou de l'UUID de l'application (vonage apps).

Notre service est maintenant associé à un numéro de téléphone. Si nous appelons ce numéro, il déclenchera le point de terminaison et le NCCO renvoyé déclenchera la synthèse vocale pour prononcer la phrase "Veuillez saisir votre code PIN suivi d'un hachage. /webhooks/answer et le NCCO renvoyé déclenchera la synthèse vocale pour prononcer la phrase "Veuillez saisir votre code PIN, suivi d'un dièse", puis attendra la saisie sur le clavier du téléphone. Saisissez "1234#" sur votre clavier, ce qui sera envoyé au point d'accès, qui lira le code PIN. /webhooks/passcode qui lira le code d'accès à six chiffres.

Scannez le code QR en haut de cet article de blog dans Google Authenticator, et vous devriez constater que les codes correspondent parfaitement !

Déploiement mondial avec Heroku

C'est une bonne chose, mais ce n'est pas très pratique de le faire tourner sur votre machine - il s'arrêtera si vous l'éteignez et si vous êtes en voyage, il est peu probable que vous laissiez un ordinateur allumé à la maison ! Il serait donc préférable de le faire fonctionner quelque part sur l'internet.

Heroku est idéal pour cela, car il permet de déployer et d'héberger facilement des services web. Un Account gratuit suffit, alors allez-y et s'inscrire et configurez-le (avec Git et le CLI Heroku). J'attends.

Modifications du code

Heroku attribuera un port aléatoire pour que l'application écoute, nous ne pouvons donc pas simplement utiliser 3000. Nous devons faire ce changement d'une ligne à totp.js pour le récupérer dans l'environnement :

const PORT = process.env.PORT || 3000

Une autre modification doit être apportée au fichier package.json pour que la commande npm start car Heroku ne saura pas autrement comment démarrer notre application ! Il suffit d'ajouter la commande node totp.js que nous avons utilisée localement à l'élément scripts. L'ensemble du fichier package.json devrait maintenant ressembler à ceci :

{
  "name": "totp",
  "version": "1.0.0",
  "description": "One Time Password by phone",
  "main": "totp.js",
  "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "nexmo": "^2.6.0",
    "otplib": "^12.0.1"
  },
  "devDependencies": {},
  "scripts": {
    "start": "node totp.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Russ Williams",
  "license": "ISC"
}

Mise en place du contrôle de source Git

Nous devons utiliser Git pour déployer sur Heroku, et c'est évidemment une bonne pratique que d'avoir un contrôle de source en place pour tout développement. Pour l'instant, nous nous contenterons d'un dépôt local, mais GitHub est gratuit et gardera votre code en sécurité tout en le rendant accessible de n'importe où dans le monde.

Tout d'abord, créez un référentiel :

git init

Ensuite, ajoutez les fichiers sources dont nous aurons besoin :

git add totp.js package.json private.key

Enfin, nous devons valider ces modifications :

git commit -m"Initial release"

Déploiement sur Heroku

Tout d'abord, nous devons créer une nouvelle application dans Heroku :

heroku create

Cela donnera à votre nouvelle application un nom généré de manière aléatoire, quelque chose comme lit-spire-15244. La commande heroku create met en place un dépôt distant (par ex. https://git.heroku.com/lit-spire-15244.git) vers lequel nous pouvons pousser du code.

Pour déployer l'application, nous devons à nouveau utiliser Git pour pousser vers ce repo distant :

git push heroku master

Cela poussera le code vers Heroku, et déclenchera un déploiement. Il exécutera en interne npm start et rapportera un statut comme https://lit-spire-15244.herokuapp.com/ deployed to Heroku. Si vous utilisez cet URI, https://lit-spire-15244.herokuapp.com/webhooks/answerdans mon cas, vous devriez voir que le service est maintenant en cours d'exécution. Une fois de plus, nous disposons d'une connexion HTTPS gratuite, ce qui est appréciable.

Si vous avez des problèmes, ou si vous voulez simplement savoir ce qui se passe, vous pouvez consulter les journaux du service à l'aide de la commande :

heroku logs --tail

Mise à jour de l'Applications Vonage

Enfin, nous devons mettre à jour le tableau de bord tableau de bord des API de Vonage. Allez dans l'onglet "Your Applications", choisissez l'application TOTP, cliquez sur "Edit" et changez les URI :

Screenshot showing update webhooks

Prochaines étapes

Comment obtenir le secret de mes Account ?

Malheureusement, Google Authenticator et la plupart des applications similaires ne le permettent pas. Une fois qu'ils ont scanné un code QR, ils ne permettent pas de récupérer le secret.

Pour les comptes G-Suite/Google (par exemple Gmail), il existe une option "Changer de téléphone" sur la page de configuration du page de configuration 2FAqui vous permet d'obtenir un nouveau code QR. Pour la plupart des autres services, vous devrez désactiver puis réactiver l'option 2FA, ou demander à l'administrateur de votre système de le faire pour vous.

Faire une capture d'écran ainsi que scanner le code QR dans l'application vous permettra d'extraire le secret et de l'utiliser avec cette application.

Comment obtenir le secret d'un code QR ?

Utilisez une application générique de scanner de code QR pour obtenir l'URI - il en existe de nombreuses pour tous les téléphones, et il peut même y en avoir une intégrée à l'application appareil photo de votre téléphone. Vous pouvez également utiliser un site web tel que https://webqr.com/ pour scanner une photo.

Le secret dont vous avez besoin est la séquence de lettres majuscules entre "secret=" et le "&" dans l'URI : otpauth://totp/Example:totp@example.com?secret=KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD&issuer=Example

Où pouvons-nous aller ?

Il existe de nombreuses façons de développer cet exemple d'application :

  • Exiger des secrets codés en dur n'est pas optimal et il serait préférable de les récupérer à partir d'une base de données côté serveur.

  • Il n'existe aucune protection contre le forçage brutal de votre code PIN si quelqu'un est prêt à effectuer 10 000 appels à cette application, il serait donc utile de mettre en place une sorte de limitation du taux d'appels

  • Il est inutile d'avoir un numéro de téléphone pour un seul secret, nous pourrions donc créer un système de menu IVR ("Appuyez sur 1 pour le code Gmail, appuyez sur 2 pour...").

  • Les codes d'accès sont sensibles au temps, donc s'il ne reste que quelques secondes avant que le code ne change, nous devrions probablement utiliser la synthèse vocale pour dire cela et attendre le prochain, plutôt que de lire un code périmé. Il vaut mieux prolonger l'appel de quelques secondes que de devoir recomposer le numéro et réessayer.

  • L'extraction manuelle de secrets à partir de codes QR craint et il existe des modules node.js (e.g. qrcode-reader) qui peuvent le faire pour nous. Si nous stockions les secrets de l'application dans une base de données, nous pourrions ajouter un simple front-end web pour s'inscrire à partir d'une capture d'écran (par ex. ce guide de Google)

  • ... ou d'un accès à l'appareil photo du téléphone et d'un peu de colle HTML5 pour capturer une image (par ex. getUserMedia) ou même analyser le code QR (par ex. ce tutoriel ou html5-qrcode) et appeler le service web d'inscription

J'espère que cela vous a donné quelques idées sur la façon dont vous pouvez utiliser les API de Vonage avec l'authentification à deux facteurs.

Partager:

https://a.storyblok.com/f/270183/200x267/a8435a2b98/russ-williams.png
Russ Williams

Russ has been arguing with computers since 1985, and now mostly wins the fights. He has worked in video games, defence and investment banking, and joined the Vonage team four days before the Coronavirus lockdown. He enjoys travel, poker, games of all sorts, science fiction, and is easily dist... ooh, squirrel!