[GO] Die Geschichte der Einführung einer Multi-Faktor-Authentifizierungsfunktion unter Verwendung eines Einmalkennworts in einer Java-Anwendung

Überblick

Hier finden Sie eine Zusammenfassung der Ergebnisse der Einführung der Einmalkennwortauthentifizierung für Java-Apps, deren Benutzerauthentifizierungsfunktion auf ID / Kennwort basiert.

Was realisiert wurde, ist "Multi-Faktor-Authentifizierung". Es wird auch das Thema der zweistufigen Authentifizierung in einem bestimmten Pay genannt. Wir sagen "Element" oder "Bühne", aber dieser Artikel befasst sich mit dem ersteren. (Siehe unten) Darüber hinaus sind die in diesem Artikel verwendeten Einmalkennwörter "zeitbasiert", sogenannte TOTP-konform (Time-based One Time Password). (Siehe unten)

Der Inhalt ist grob in zwei Teile unterteilt: eine "Einstellungsfunktion", mit der sich der Benutzer mit einem Einmalkennwort authentifizieren kann, und eine "Authentifizierungsfunktion", die für Benutzer ausgeführt wird, deren Einstellungen gültig sind.

Wir gingen auch davon aus, dass Google Authenticator zur Ausgabe des Einmalkennworts verwendet wird. Es gibt mehrere Apps zur einmaligen Kennwortausgabe, die jedoch jeweils leicht unterschiedliche Spezifikationen haben.

Über die drei Elemente der Authentifizierung

Es ist ein wenig abseits des Themas, aber die Authentifizierung besteht in erster Linie aus drei Komponenten.

  1. Etwas, das du ** weißt **
  1. Etwas, das du ** hast **
  1. Etwas, das du bist (biologisches Element) ――Es ist ein Element aufgrund der physischen Eigenschaften der Person selbst. Zum Beispiel Fingerabdrücke und Venen.

Die Authentifizierung mit einer Kombination dieser zwei oder mehr Elemente wird als "Mehrelementauthentifizierung" bezeichnet. Daher sind die häufig gestellten "Passwort + geheime Frage" beide "Wissenselemente", also eine Einzelelementauthentifizierung.

Da die häufig gehörte "zweistufige Authentifizierung" die Elemente nicht berührt, nur weil es Phasen in der Authentifizierungsphase gibt, scheint der Fall der zweistufigen Authentifizierung unter Verwendung eines einzelnen Elements hinsichtlich der Sicherheit nicht stark zu sein. In vielen Fällen scheint es jedoch eine schrittweise Authentifizierung mit zwei oder mehr Faktoren anzuzeigen.

Informationen zur Authentifizierungsmethode

Ich möchte das in diesem Artikel behandelte TOTP (Time-based One Time Password) überprüfen.

TOTP ist eine Methode, die beim Generieren eines Einmalkennworts ** Zeit ** als Generierungselement verwendet. Die technischen Spezifikationen sind in RFC6238 definiert.

Sowohl die Seite, die die Authentifizierung anfordert (als Client bezeichnet), als auch die Seite, die die Authentifizierung durchführt (als Server bezeichnet), generieren ein Einmalkennwort, das ab dem auf Unix Epoch basierenden Zeitpunkt für einen bestimmten Zeitraum gültig ist. Die Gültigkeit wird überprüft, indem die vom Client bzw. vom Server generierten Einmalkennwörter abgeglichen werden. Außerdem ist es nicht "einmalig", da es für einen bestimmten Zeitraum gültig ist. Wenn Sie keine Maßnahmen ergreifen, wird diese innerhalb eines bestimmten Zeitraums so oft wirksam, wie Sie möchten. Dies soll die Schwäche der TOTP-Methode sein.

Zusätzlich zur Zeit wird der vom Server im Voraus an den Client ausgegebene ** gemeinsame Schlüssel ** verwendet, um das Einmalkennwort zu generieren. Am Beispiel von Google Authenticator wird beim Aktivieren der Multi-Faktor-Authentifizierung für einen Webdienst der vom Webdienst ausgegebene QR-Code zuerst von Google Authenticator gelesen. Dieser QR-Code besteht aus einem URI, der der Google Authenticator-Spezifikation entspricht, jedoch einen gemeinsamen Schlüssel enthält. Dadurch wird der gemeinsame Schlüssel sowohl auf dem Webdienst (Server) als auch auf dem Google Authenticator (Client) gespeichert. Hierbei ist zu beachten, dass der QR-Code einen gemeinsamen Schlüssel enthält. Wenn er gestohlen wird, kann sich eine andere Person authentifizieren. Daher sollte der Bildschirm mit dem QR-Code nicht von anderen gestohlen werden.

Über die gültige Zeit des Einmalpassworts

Aus der Schlussfolgerung geht hervor, dass es oft 30 Sekunden sind. Dies wird auch in RFC6238 wie folgt geschrieben, und es scheint, dass das Gleichgewicht zwischen Sicherheit und Benutzerfreundlichkeit gut ist.

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.

Diese 30 Sekunden werden auch als ** Schritt ** bezeichnet. Unix Epoch wird verwendet, um die Schritte zu berechnen. Dies bedeutet, dass auf jedem Gerät gleichzeitig dasselbe Einmalkennwort generiert wird. Es wird nicht von Zeitzonen oder anderen Faktoren beeinflusst.

Wenn der Client jedoch ein Terminal wie ein "Einmalkennwortgenerator" ist, der über das Internet nicht die richtige Zeit abrufen kann, wie beispielsweise ein Smartphone, muss das Phänomen berücksichtigt werden, dass sich die Zeit allmählich verschiebt. Daher scheinen die zur Überprüfung verwendeten Schritte nicht genau diese Schritte zu sein, aber Richtlinien wie das Zulassen eines vorherigen und eines vorherigen Schritts werden häufig festgelegt. Die Bibliothek, die dieses Mal verwendet wird, ist so konzipiert, dass "ein Schritt vorher und nachher" möglich ist. Die tatsächliche Überprüfung lautet also wie folgt.

Zeit einmaliges Passwort Überprüfungszeitpunkt Prüfergebnis
00:00:00 ~ 00:00:29 111111 NG
00:00:30 ~ 00:00:59 222222 OK
00:01:00 ~ 00:01:29 333333 Überprüfen Sie hier OK
00:01:30 ~ 00:01:59 444444 OK
00:02:00 ~ 00:02:29 555555 NG

Über Google Authenticator

Überprüfen Sie die Spezifikationen von Google Authenticator. Details sind in GitHub geschrieben, daher werde ich mir die wichtigen Punkte in der Implementierung ansehen.

Implementierung

Einführung in die Bibliothek

GoogleAuth

Ich habe GoogleAuth verwendet, das die komplizierte Verarbeitung abschließt, die für die einmalige Kennwortgenerierung erforderlich ist. Ich denke, dass es kein Problem gibt, nur die README-Datei für den normalen Gebrauch zu lesen.

Da es sich um ein Maven-Projekt handelte, habe ich Folgendes zu pom.xml hinzugefügt. Es scheint, dass es auch Gradle unterstützt.

pom.xml


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

jquery-qrcode

Ich habe jquery-qrcode verwendet, um den QR-Code zu generieren. Es wird von JavaScript als HTML5 "canvas" ausgegeben, daher bin ich dankbar, dass keine Bilddateien verwaltet werden müssen.

Wie Sie anhand des Namens erraten können, benötigen Sie außerdem jQuery. Der Hauptgrund für die Auswahl ist, dass das Projekt ursprünglich jQuery verwendet hat. Daher halte ich es nicht für erforderlich, jQuery für diesen Zweck einzuführen.

Dies ist auch in der README beschrieben. Ich habe das GitHub-Repository geklont, die js-Datei in das Projektpaket kopiert und Folgendes ausgeführt:

sample.html


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

Einstellfunktion

Fall zu aktivieren

fließen

sample.png

Beachten Sie, dass Benutzeroperationen in der Mitte des Flusses eingegeben werden. Ich denke, es ist vorzuziehen, es so zu gestalten, dass der Benutzer nicht erwartet, dass es wie erwartet funktioniert. Anstatt es unmittelbar nach dem Empfang einer Aktivierungsanforderung zu aktivieren, ist der Ablauf daher so, dass er aktiviert wird, wenn bestätigt wird, dass der Benutzer den erwarteten Vorgang ausgeführt hat.

Code

Gemeinsame Schlüsselausgabe

Geben Sie den allgemeinen Schlüssel wie folgt aus. Der hier ausgegebene allgemeine Schlüssel wird später verwendet. Behalten Sie ihn daher in einer Sitzungsvariablen bei.

Sample.java


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

Außerdem wird ein URI generiert, der den ausgegebenen gemeinsamen Schlüssel enthält. Stellen Sie "serviceName" und "userId" entsprechend ein. (Beachten Sie, dass keiner von beiden : enthalten kann.)

Sample.java


String uri = "otpauth://totp/" + serviceName + ":" + userId + "?secret=" + secret + "&issuer=" + serviceName;
QR-Code-Anzeige

Konvertieren Sie den URI einschließlich des gemeinsamen Schlüssels wie folgt in einen QR-Code. Die Bibliothek verfügt auch über ein Beispiel (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: '{Generierter URI}'
        }
    );
});
</script>
</body>
Einmalige Passwortüberprüfung

Richten Sie auf dem Bildschirm für die Anzeige des QR-Codes ein Formular zur Eingabe eines Einmalkennworts ein. Fordern Sie den Benutzer auf, den QR-Code mit Google Authenticator zu lesen und dann das generierte Einmalkennwort einzugeben. Bei dieser einmaligen Kennwortüberprüfung wird davon ausgegangen, dass sich der Nutzer erfolgreich bei Google Authenticator registriert hat, und die Multi-Faktor-Authentifizierung für diesen Nutzer aktiviert.

Überprüfen Sie Folgendes.

Sample.java


String secret = {Gemeinsamer Schlüssel im vorherigen Ablauf};
int verificationCode = Integer.parseInt({Einmaliges Passwort eingegeben});
GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorize(secret, verificationCode);

Wenn das Überprüfungsergebnis korrekt ist, speichern Sie den allgemeinen Schlüssel in einem dauerhaften Bereich wie z. B. DB, indem Sie ihn dem Benutzer zuordnen.

Sicherungscode ausgeben

Da Google Authenticator eine Smartphone-App ist, kann effektiv ein Sicherungscode ausgegeben werden, der anstelle des Einmalkennworts verwendet werden kann, falls das Smartphone unbrauchbar wird, dh das Einmalkennwort kann nicht ausgegeben werden.

Die Bibliothek gibt 5 zufällige Ganzzahlen aus, wenn Sie Folgendes tun:

Sample.java


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

Speichern wir dies zusammen mit dem gemeinsamen Schlüssel im persistenten Bereich.

Fall zu deaktivieren

Mit der Bibliothek hat nichts Besonderes zu tun. Sie müssen lediglich den allgemeinen Schlüssel und den Sicherungscode löschen, die im persistenten Bereich gespeichert sind.

Authentifizierungsfunktion

fließen

sample2.png

Code

Einmalige Passwortüberprüfung

Gehen Sie genauso vor wie bei der Überprüfung, die Sie in der Einstellungsfunktion aktiviert haben. An diesem Punkt denke ich, dass sich der gemeinsame Schlüssel in der Datenbank usw. befindet. Überprüfen Sie ihn daher mit dem eingegebenen Einmalkennwort.

String secret = {Gemeinsamer Schlüssel von DB usw. erhalten};
int verificationCode = Integer.parseInt({Einmaliges Passwort eingegeben});
GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorize(secret, verificationCode);

Darüber hinaus scheint es aus Sicherheitsgründen wünschenswert zu sein, das Einmalkennwort gleichzeitig mit dem Kennwort und vor dem Kennwort zu überprüfen, nicht bei der schrittweisen Überprüfung. Ich habe auf den Artikel [hier] verwiesen (https://blog.ohgaki.net/2fa-totp-hotp-which-is-safer).

Zusammenfassung

Als ich von der Multi-Faktor-Authentifizierung hörte, hatte ich den Eindruck, dass die Entwicklung aufgrund der problematischen Einstellungen schwierig war, aber ich stellte fest, dass eine Bibliothek, die die Sprache unterstützt, leicht einzuführen wäre. Durch die tatsächliche Einführung war es auch ein großer Vorteil, dass ich verstehen konnte, wie es funktioniert, selbst wenn ich es bei der Nutzung des Dienstes festgelegt habe. Diese Erfahrung möchte ich bei der Entwicklung des nächsten Dienstes nutzen.

Recommended Posts

Die Geschichte der Einführung einer Multi-Faktor-Authentifizierungsfunktion unter Verwendung eines Einmalkennworts in einer Java-Anwendung
Die Geschichte des Erstellens einer Datenbank mithilfe der Google Analytics-API
Die Geschichte, schmerzhafte Augen zu sehen, wenn man sich süß umschaut (versuchen Sie, die Authentifizierung mit django-allauth einzuführen).
Finden Sie den optimalen Wert der Funktion mit einem genetischen Algorithmus (Teil 1)
Die Geschichte des erneuten Bereitstellens des Anwendungsservers
Die Geschichte des Exportierens eines Programms
Die Geschichte der Entwicklung einer WEB-Anwendung, die automatisch Fangkopien generiert [MeCab]
Was Java-Benutzer davon gehalten haben, die Go-Sprache für einen Tag zu verwenden
Hinweis zur Verwendung der Python-Eingabefunktion
Die Geschichte der Verarbeitung A von Blackjack (Python)
Die Geschichte der Erstellung einer Webanwendung, die umfangreiche Lesungen mit Django aufzeichnet
Holen Sie sich den Aufrufer einer Funktion in Python
Die Geschichte eines Mel-Icon-Generators
Dies ist ein Beispiel für eine Funktionsanwendung im Datenrahmen.
Die Geschichte des Starts eines Minecraft-Servers von Discord
Geschichte der Verwendung von Resonas Software-Token mit 1Password
#Eine Funktion, die den Zeichencode einer Zeichenfolge zurückgibt
Die Geschichte eines neuronalen Netzwerks der Musikgeneration
Zeichnen auf Jupyter mit der Plot-Funktion von Pandas
Eine Geschichte über die Änderung des Master-Namens von BlueZ
[Python] Maskiere das Bild mit Pillow zu einem Kreis
Zip 4 Gbyte Problem ist eine Geschichte der Vergangenheit
Eine Geschichte, die die Lieferung von Nico Nama analysierte.
Die Geschichte der Verwendung von Circleci zum Bau vieler Linux-Räder