Implémentation de l'authentification en deux étapes en Java

Overview J'ai toujours voulu implémenter l'authentification en deux étapes, mais c'était plus facile que prévu en raison de l'existence d'une bonne bibliothèque.

GoogleAuth (bibliothèque côté serveur pour l'authentification en deux étapes)

https://github.com/wstrange/GoogleAuth

GoogleAuth est une bibliothèque Java côté serveur qui crée un mot de passe à usage unique basé sur l'heure (TOTP) tel que défini dans la RFC6238.

Si vous implémentez le côté serveur à l'aide de la bibliothèque ci-dessus, vous pouvez authentifier l'utilisateur à l'aide du jeton à usage unique émis par une application telle que Google Authenticator fourni par Google.

Google Authenticator pour iOS

https://itunes.apple.com/jp/app/google-authenticator/id388497605?mt=8

Version Android Google Authenticator

https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=ja

Google Authenticator peut également être utilisé car il crée un jeton unique selon les spécifications TOTP.

Flux général de la certification en deux étapes

Je pense que le flux sera le suivant.

two-factor-auth-seq.png

Exemple de code

https://github.com/yuizho/two-factor-auth-sample

Il s'agit du code d'implémentation de la partie Serveur dans le diagramme de séquence ci-dessus.

Le langage utilise Java.

Le processus d'enregistrement des informations utilisateur est triché en utilisant la carte de Singleton au lieu de DB.

Exemple d'explication de code

Il s'agit de l'explication de l'exemple de code, ou presque de la façon d'utiliser la bibliothèque (Google Auth).

Émission et sauvegarde de SecretKey

Vous pouvez émettre une clé secrète pour "user_id" avec le code ci-dessous et l'enregistrer dans une base de données.

GoogleAuthenticator gAuth = new GoogleAuthenticator();
GoogleAuthenticatorKey key = gAuth.createCredentials("user_id");

Avant d'exécuter le code ci-dessus, vous devez effectuer les préparatifs suivants.

Préparer une classe d'implémentation pour ICredentialRepository

Lorsque vous exécutez le createCredentials ci-dessus, GoogleAuth appelle la méthode saveUserCredentials de la classe d'implémentation de ICredentialRepository pour enregistrer la clé secrète.

public class MyCredentialRepository implements ICredentialRepository {
    // ...
    @Override
    public void saveUserCredentials(String userId, String secretKey, int validationCode, List<Integer> scratchCodes) {
        //Décrivez le processus pour enregistrer la clé secrète avec userId comme clé
    }
}

Au fait, scratchCodes est un code à utiliser lorsque l'utilisateur perd le terminal, et il semble que 5 soient émis par défaut. https://github.com/wstrange/GoogleAuth#scratch-codes

Je ne pouvais pas tout à fait comprendre à quoi le validationCode était censé être (similaire à scratchCodes?) Si vous savez, apprenez-moi s'il vous plaît: arc

Je ne l'ai pas fait dans l'exemple de code, mais je pense que c'est une bonne idée d'implémenter le traitement de ces valeurs si nécessaire.

Préparation pour Java Service Loader

GoogleAuth implémente ICredentialRepository à l'aide de API Java ServiceLoader lors de l'exécution de createCredentials. Obtenez la classe et enregistrez le secretKey.

Créez un dossier META-INF / services à un emplacement où passe le chemin de classe, par exemple sous src / resource, et créez un fichier texte appelé com.warrenstrange.googleauth.ICredentialRepository.

Si vous décrivez le nom de classe d'implémentation de ICredentialRepository dans le fichier créé comme suit, Google Auth utilisera cette classe.

io.github.yuizho.twofactorauth.MyCredentialRepository

Retour d'informations secrètes

Lors du chargement des informations secrètes, y compris la clé secrète générée dans Google Authenticator, générez un URI au format suivant et convertissez-le en code QR.

otpauth://totp/<userId>?secret=<secretKey>&issuer=<applicationName>

e.g. otpauth://totp/test_user?secret=ZYWAZKOQLG3YHBSZ&issuer=two-factor-auth-sample

Voir ci-dessous pour plus de détails sur le format URI. https://github.com/google/google-authenticator/wiki/Key-Uri-Format

Vérification des jetons

Vous pouvez obtenir le secretKey pour "user_id" à partir de la destination de sauvegarde comme ci-dessous, générer un jeton et vérifier s'il correspond au jeton transmis (celui obtenu avec Google Authenticator).

GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorizeUser("user_id", token);

À ce stade, GoogleAuth appelle la méthode getSecretKey de la classe d'implémentation de ICredentialRepository pour acquérir le secretKey de la même manière que lors de l'enregistrement de secretKey.

public class MyCredentialRepository implements ICredentialRepository {
    // ...
    @Override
    public String getSecretKey(String userId) {
        //Implémentation du processus d'obtention de secretKey de la table avec userId comme clé et de retour
    }
}

Après cela, il générera un jeton basé sur la clé secrète acquise par Google Auth et l'horodatage actuel, et le comparera avec le jeton transmis au deuxième argument de GoogleAuthenticator # authorizeUser.

Résumé

Il était donc relativement facile de mettre en œuvre l'authentification en deux étapes.

Cette fois, GoogleAuth est utilisé pour la bibliothèque côté serveur, mais vous pouvez bien sûr l'implémenter vous-même sans utiliser la bibliothèque.

Dans ce cas, je pense que vous devez implémenter le processus de génération de token TOTP tout en vous référant au RFC suivant, etc. (un exemple de code est également disponible). https://tools.ietf.org/html/rfc6238

Recommended Posts

Implémentation de l'authentification en deux étapes en Java
Implémenter l'authentification de base en Java
Implémenter une combinaison de mathématiques en Java
2 Implémentez une analyse syntaxique simple en Java
Implémenter l'envoi d'e-mails en Java
Implémenter un tri rapide de type fonction en Java
Certification en deux étapes Réalisation JAVA (TOTP)
Implémentez rm -rf en Java.
Implémenter la signature XML en Java
Implémenter un test piloté par table dans Java 14
3 Implémentez un interpréteur simple en Java
Implémenter reCAPTCHA v3 dans Java / Spring
Implémenter la fonction PHP implode en Java
Essayez d'implémenter Yuma en Java
1 Implémentez une analyse de phrase simple en Java
Comment implémenter le calcul de la date en Java
Comment implémenter le filtre de Kalman par Java
Implémenter l'autorisation API Gateway Lambda dans Java Lambda
Partition en Java
Essayez d'implémenter l'ajout n-aire en Java
Changements dans Java 11
Janken à Java
Comment appliquer les conventions de codage en Java
Implémenter quelque chose comme une pile en Java
Taux circonférentiel à Java
FizzBuzz en Java
Lire JSON en Java
Implémentation de l'interpréteur par Java
Faites un blackjack avec Java
Application Janken en Java
Programmation par contraintes en Java
Mettez java8 dans centos7
NVL-ish guy en Java
Joindre des tableaux en Java
"Hello World" en Java
Interface appelable en Java
Fonctions Azure en Java
Formater XML en Java
Simple htmlspecialchars en Java
Implémentation Boyer-Moore en Java
Hello World en Java
Utiliser OpenCV avec Java
Mémorandum WebApi avec Java
Détermination de type en Java
Exécuter des commandes en Java (ping)
Divers threads en java
Implémentation du tri de tas (en java)
API Zabbix en Java
Art ASCII à Java
Comparer des listes en Java
POST JSON en Java
Exprimer l'échec en Java
Implémenter CustomView dans le code
Créer JSON en Java
Manipulation de la date dans Java 8
Nouveautés de Java 8
Utiliser PreparedStatement en Java
Nouveautés de Java 9,10,11
Exécution parallèle en Java