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.
C'est un peu hors sujet, mais l'authentification comporte trois éléments en premier lieu.
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.
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.
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 |
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.
ServiceName:[email protected]
secret
(obligatoire)(fortement recommandé) --Nom du service, de préférence le même que le libellé
ServiceName`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>
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.
É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;
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>
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.
É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.
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.
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.
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.