L'histoire de l'introduction d'une fonction d'authentification multifacteur utilisant un mot de passe à usage unique dans une application Java

Aperçu

Voici un résumé des résultats de l'introduction de l'authentification par mot de passe à usage unique dans les applications Java qui ont une fonction d'authentification utilisateur basée sur l'ID / le mot de passe.

Ce qui a été réalisé est "l'authentification multifacteur". Cela s'appelle également le sujet de l'authentification en deux étapes dans un certain Pay. Nous disons «élément» ou «étape», mais cet article traite du premier. (Voir ci-dessous) En outre, les mots de passe à usage unique utilisés dans cet article sont «basés sur l'heure», ce que l'on appelle TOTP (Time-based One Time Password). (Voir ci-dessous)

Le contenu est grossièrement divisé en deux parties: une «fonction de paramétrage» qui permet à l'utilisateur de s'authentifier avec un mot de passe à usage unique, et une «fonction d'authentification» qui est effectuée pour les utilisateurs dont les paramètres sont valides.

Nous avons également supposé que Google Authenticator serait utilisé pour émettre le mot de passe à usage unique. Il existe plusieurs applications émettant un mot de passe à usage unique, mais chacune a des spécifications légèrement différentes.

À propos des trois éléments de l'authentification

C'est un peu hors sujet, mais l'authentification comporte trois éléments en premier lieu.

  1. Quelque chose que vous ** savez **
  1. Quelque chose que vous ** avez **
  1. Quelque chose que vous ** êtes ** (élément biologique) ――Il s'agit d'un élément dû aux caractéristiques physiques de la personne elle-même. Par exemple, les empreintes digitales et les veines.

L'authentification avec une combinaison de ces deux éléments ou plus est appelée "authentification multi-éléments". Par conséquent, les «mot de passe + question secrète» fréquemment posées sont tous deux des «éléments de connaissance», il s'agit donc d'une authentification à un seul élément.

Aussi, comme l '«authentification en deux étapes» fréquemment entendue ne touche pas aux éléments du seul fait qu'il y a des étapes dans la phase d'authentification, il semble que le cas de l'authentification en deux étapes utilisant un seul élément n'est pas fort en termes de sécurité. Cependant, dans de nombreux cas, il semble indiquer une authentification par étapes avec deux facteurs ou plus.

À propos de la méthode d'authentification

Je voudrais passer en revue le TOTP (Time-based One Time Password) couvert dans cet article.

TOTP est une méthode qui utilise ** time ** comme élément de génération lors de la génération d'un mot de passe à usage unique. Les spécifications techniques sont définies dans la RFC6238.

Le côté demandant l'authentification (appelé un client) et le côté effectuant l'authentification (appelé un serveur) génèrent un mot de passe à usage unique qui est valide pendant une certaine période de temps à partir de l'heure basée sur Unix Epoch. , La validité est vérifiée en faisant correspondre les mots de passe à usage unique générés respectivement par le client et le serveur. De plus, il n'est pas «unique» car il est valable pendant une certaine période. Si vous ne prenez pas de mesures, il sera efficace autant de fois que vous le souhaitez dans un certain laps de temps. On dit que c'est la faiblesse de la méthode TOTP.

En plus du temps, la ** clé commune ** émise par le serveur au client à l'avance est utilisée pour générer le mot de passe à usage unique. En prenant Google Authenticator comme exemple, lors de l'activation de l'authentification multifacteur pour un service Web, le code QR émis par le service Web est d'abord lu par Google Authenticator. Ce code QR se compose d'un URI conforme à la spécification Google Authenticator, mais il contient une clé commune. Cela stocke la clé commune à la fois sur le service Web (serveur) et sur Google Authenticator (client). Il convient de noter ici que le code QR contient une clé commune, donc s'il est volé, il sera possible à quelqu'un d'autre de s'authentifier. Par conséquent, l'écran affichant le code QR ne doit pas être volé par d'autres.

À propos de l'heure de validité du mot de passe à usage unique

De la conclusion, il semble que ce soit souvent 30 secondes. Ceci est également écrit dans la RFC6238 comme suit, et il semble que l'équilibre entre la sécurité et l'utilisabilité est bon.

We RECOMMEND a default time-step size of 30 seconds. This default value of 30 seconds is selected as a balance between security and usability.

Ces 30 secondes sont également appelées ** étape **. Unix Epoch est utilisé pour calculer les étapes. Cela signifie que le même mot de passe à usage unique sera généré sur n'importe quel appareil en même temps. Il n'est pas affecté par les fuseaux horaires ou d'autres facteurs.

Cependant, si le client est un terminal tel qu'un «générateur de mots de passe à usage unique» qui ne peut pas obtenir l'heure correcte via Internet, tel qu'un smartphone, il faut considérer le phénomène que l'heure change progressivement. Par conséquent, il semble que les étapes utilisées pour la vérification ne soient pas exactement ces étapes, mais des politiques telles que permettre une étape avant et après sont souvent décidées. La bibliothèque utilisée cette fois-ci est conçue pour permettre "une étape avant et après", donc la vérification réelle est la suivante.

temps Mot de passe à usage unique Calendrier de vérification résultat de l'inspection
00:00:00 ~ 00:00:29 111111 NG
00:00:30 ~ 00:00:59 222222 OK
00:01:00 ~ 00:01:29 333333 Vérifiez ici OK
00:01:30 ~ 00:01:59 444444 OK
00:02:00 ~ 00:02:29 555555 NG

À propos de Google Authenticator

Vérifiez les spécifications de Google Authenticator. Les détails sont écrits dans GitHub, je vais donc examiner les points importants de la mise en œuvre.

la mise en oeuvre

Présentation de la bibliothèque

GoogleAuth

J'ai utilisé GoogleAuth, qui englobe le traitement complexe requis pour la génération de mot de passe à usage unique. Je pense qu'il n'y a aucun problème à lire le README pour une utilisation normale.

Puisqu'il s'agissait d'un projet Maven, j'ai ajouté ce qui suit à pom.xml. Il semble qu'il prend également en charge Gradle.

pom.xml


<dependency>
    <groupId>com.warrenstrange</groupId>
    <artifactId>googleauth</artifactId>
    <version>1.1.5</version>
</dependency>

jquery-qrcode

J'ai utilisé jquery-qrcode pour générer le code QR. Il est sorti en HTML5 canvas par JavaScript, donc je suis reconnaissant qu'il n'y ait pas besoin de gérer les fichiers image.

De plus, comme vous pouvez le deviner d'après le nom, vous avez besoin de jQuery. La principale raison de la sélection est que le projet utilisait à l'origine jQuery, donc je ne pense pas qu'il soit nécessaire d'introduire jQuery à cette fin.

Ceci est également décrit dans le README. J'ai cloné le référentiel GitHub, copié le fichier js dans le package du projet et effectué les opérations suivantes:

sample.html


<script type="text/javascript" src="/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="/jquery.qrcode.min.js"></script>

Fonction de réglage

Cas à activer

couler

sample.png

Une chose à garder à l'esprit est que les opérations utilisateur sont saisies au milieu du flux. Je pense qu'il est préférable de le concevoir de manière à ce que l'utilisateur ne s'attende pas à ce qu'il fonctionne comme prévu. Par conséquent, au lieu de l'activer immédiatement après avoir reçu une demande d'activation, le flux est tel qu'il est activé lorsqu'il est confirmé que l'utilisateur a effectué l'opération attendue.

code

Émission de clé commune

Émettez la clé commune comme suit. La clé commune émise ici sera utilisée plus tard, alors conservez-la dans une variable de session.

Sample.java


GoogleAuthenticator gAuth = new GoogleAuthenticator();
GoogleAuthenticatorKey key = gAuth.createCredentials();
String secret = key.getKey();

Il génère également un URI qui inclut la clé commune émise. Définissez serviceName et ʻuserIdcomme il convient. (Notez que ni l'un ni l'autre ne peuvent inclure:`)

Sample.java


String uri = "otpauth://totp/" + serviceName + ":" + userId + "?secret=" + secret + "&issuer=" + serviceName;
Affichage du code QR

Faites de l'URI comprenant la clé commune un code QR comme suit. La bibliothèque contient également un exemple (https://github.com/jeromeetienne/jquery-qrcode/blob/master/examples/basic.html).

sample.html


<body>
<div id="qrcode"></div>
<script type="text/javascript" src="/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="/jquery.qrcode.min.js"></script>
<script>
$(function() {
    $('#qrcode').qrcode(
        {
            width: 150,
            height: 150,
            text: '{URI généré}'
        }
    );
});
</script>
</body>
Vérification du mot de passe unique

Configurez un formulaire de saisie de mot de passe à usage unique sur l'écran d'affichage du code QR. Invitez l'utilisateur à lire le code QR avec Google Authenticator, puis entrez le mot de passe à usage unique généré. Avec cette vérification de mot de passe unique, nous supposons que l'utilisateur s'est correctement enregistré auprès de Google Authenticator et activons l'authentification multifacteur pour cet utilisateur.

Vérifiez comme suit.

Sample.java


String secret = {Clé commune détenue dans le flux précédent};
int verificationCode = Integer.parseInt({Mot de passe à usage unique saisi});
GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorize(secret, verificationCode);

Si le résultat de la vérification est correct, enregistrez la clé commune dans une zone persistante telle que DB en l'associant à l'utilisateur.

Émission d'un code de sauvegarde

Étant donné que Google Authenticator est une application pour smartphone, il est efficace d'émettre un code de sauvegarde qui peut être utilisé à la place du mot de passe à usage unique au cas où le smartphone deviendrait inutilisable, c'est-à-dire que le mot de passe à usage unique ne pourrait pas être émis.

Si vous procédez comme suit, la bibliothèque émettra 5 entiers aléatoires.

Sample.java


GoogleAuthenticatorKey key = gAuth.createCredentials();
List<Integer> scratchCodes = key.getScratchCodes();

Sauvegardons ceci avec la clé commune dans la zone persistante.

Cas à désactiver

Il n'y a rien de spécial à voir avec la bibliothèque. Tout ce que vous avez à faire est de supprimer la clé commune et le code de sauvegarde stockés dans la zone persistante.

Fonction d'authentification

couler

sample2.png

code

Vérification du mot de passe unique

Faites la même chose que la validation que vous avez effectuée lorsque vous l'avez activée dans la fonction des paramètres. À ce stade, je pense que la clé commune est dans la base de données, etc., alors vérifiez-la en utilisant le mot de passe à usage unique saisi.

String secret = {Clé commune obtenue de DB etc.};
int verificationCode = Integer.parseInt({Mot de passe à usage unique saisi});
GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorize(secret, verificationCode);

De plus, il semble qu'il soit souhaitable pour la sécurité de vérifier le mot de passe à usage unique en même temps que le mot de passe et avant le mot de passe, pas dans la vérification par étapes. J'ai fait référence à l'article ici.

Résumé

Quand j'ai entendu parler de l'authentification multifacteur, j'ai eu l'impression que le développement était difficile en raison des paramètres gênants, mais j'ai trouvé que s'il y avait une bibliothèque prenant en charge le langage, ce serait facile à introduire. De plus, en l'introduisant, c'était un grand avantage que je suis devenu capable de comprendre comment cela fonctionne même lorsque je l'ai configuré lors de l'utilisation du service. Je voudrais profiter de cette expérience lors du développement du prochain service.

Recommended Posts

L'histoire de l'introduction d'une fonction d'authentification multifacteur utilisant un mot de passe à usage unique dans une application Java
L'histoire de la création d'une base de données à l'aide de l'API Google Analytics
L'histoire de voir des yeux douloureux en regardant gentiment autour de l'authentification (essayez d'introduire l'authentification à l'aide de django-allauth)
Trouvez la valeur optimale de la fonction à l'aide d'un algorithme génétique (partie 1)
L'histoire du remontage du serveur d'application
L'histoire de l'exportation d'un programme
L'histoire du développement d'une application WEB qui génère automatiquement des copies de capture [MeCab]
Ce que les utilisateurs de Java ont pensé d'utiliser le langage Go pendant une journée
Un mémorandum sur l'utilisation de la fonction d'entrée de Python
L'histoire du traitement A du blackjack (python)
L'histoire de la création d'une application Web qui enregistre des lectures approfondies avec Django
Récupérer l'appelant d'une fonction en Python
L'histoire de la création d'un générateur d'icônes mel
Ceci est un exemple d'application de fonction dans dataframe.
L'histoire du lancement d'un serveur Minecraft depuis Discord
Histoire de l'utilisation du jeton logiciel de Resona avec 1Password
#Une fonction qui renvoie le code de caractère d'une chaîne de caractères
L'histoire de la création d'un réseau neuronal de génération musicale
Dessinez sur Jupyter en utilisant la fonction de tracé des pandas
Une histoire sur le changement du nom principal de BlueZ
[Python] Masquez l'image dans un cercle à l'aide de Pillow
Le problème Zip 4 Gbyte est une histoire du passé
Une histoire qui a analysé la livraison de Nico Nama.
L'histoire de l'utilisation de Circleci pour construire des roues Manylinux