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.
Es ist ein wenig abseits des Themas, aber die Authentifizierung besteht in erster Linie aus drei Komponenten.
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.
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.
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 |
Überprüfen Sie die Spezifikationen von Google Authenticator. Details sind in GitHub geschrieben, daher werde ich mir die wichtigen Punkte in der Implementierung ansehen.
ServiceName:[email protected]
secret
(erforderlich)issuer
(sehr zu empfehlen)
--Service-Name, vorzugsweise identisch mit der Bezeichnung "ServiceName"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>
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.
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;
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>
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.
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.
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.
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).
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