Ich wollte immer, dass ein Hacker das Passwort eines anderen auf der Website nicht knacken kann.
Wenn ein Benutzer beispielsweise einem Hacker damit prahlt, dass sein Passwort nur aus Zahlen besteht, verliert der Benutzer bald sein Konto.
Aber was ist, wenn der Benutzer seiner Frau sein Passwort telefonisch mitteilt und der Hacker es hört?
Was?! Kennt der Hacker das Passwort? Das alles ist ein Fiasko. Können Sie einem solchen Benutzer helfen, die Entführung seines Kontos zu erschweren? Diese Frage hat mich immer beunruhigt und ich glaube, ich habe einen Weg gefunden, dies zu tun. Oder es wiederentdeckt, wie es oft der Fall ist. Schließlich ist alles schon lange vor uns erfunden worden.
Einleitend
- Der Benutzer möchte ein Passwort "12345" auf der Site haben.
- Ein Hacker kann dieses Passwort leicht erraten.
- Der Benutzer muss sich jedoch anmelden und der Hacker nicht. Auch wenn der Hacker den Login und das Passwort kennt.
- und keine SMS mit Geheimcodes und Vermittlern in Form von Zusatzdiensten. Nur der Benutzer und Ihre Site mit einer Anmeldeseite.
- und es wird auch relativ sicher sein, Ihrer Frau in einem Obus zu sagen: "Galya, ich habe das Passwort auf der Website für unsere Login Alice in 123456 geändert - sie sagen, es ist beliebter als unser 12345". Und haben Sie keine Angst, dass Ihr Konto in einer Sekunde gehackt wird.
Wie funktioniert die Methode? Alle Einzelheiten sind unter dem Schnitt.
Was ist notwendig?
- Das Konzept erklärt nur die Authentifizierungsmethode
- Für die Implementierung müssen nur " Benutzername ", " Passwort ", " salt1 " und " salt2 " gespeichert werden . Ja, zwei Salze.
- Verzichten Sie auf Protokolltabellen und Zähler in Redis
- Wir werden keine Tabellen mit IP-Adressen führen
- Wir werden keine SMS verwenden
- Anmeldeversuche werden nicht blockiert. Wie Sie aus meinem letzten erfolglosen Versuch wissen, ist es sinnlos, den Zugang zu blockieren - selbst wenn ein Hacker ein Zeitlimit hat, wird er einfach anfangen, Passwörter von mehreren Benutzern gleichzeitig zu verletzen. Darüber hinaus leidet der Benutzer selbst unter den Einschränkungen. Rufen Sie ihn nicht zur Unterstützung an, um sich mit coolen Bildern auf Ihrer Website anzumelden?
- Der Benutzer kann das Kennwort jederzeit ändern und auf anderen Geräten ungültig machen. Dies ist eine gängige Regel, aber ich denke, es ist erwähnenswert.
- Sie können das Erraten eines Passworts mithilfe eines Wörterbuchs für einen Hacker erschweren (optional, wird unten erwähnt).
Methodenessenz
Erlauben Sie dem Benutzer, das Passwort "12345" zu haben, und das Brechen dieses Passworts sollte erschwert werden. Zum Beispiel, wie man ein Passwort errät, das wie ein Hash aussieht.
Wie?
Stellen Sie sich vor, der Browser hätte immer ein eindeutiges Salt, mit dem das Passwort gesalzen werden könnte. Salz für jeden Benutzer. Warum wird es benötigt? Verschlüsseln. Wenn Sie beispielsweise die Zeichenfolge "12345" mit Salz "Salzsalz" in argon2id verschlüsseln, erhalten Sie "$ argon2id $ v = 19 $ m = 16, t = 2, p = 1 $ c2FsdHNhbHQ $ jX94laSi6vo9AhS + bHwbkg". Ändern Sie das Salz und der Hasch wird anders sein. Ein Algorithmus verschlüsselt dieselben Passwörter unterschiedlich, indem für jedes ein anderes Salt verwendet wird. Gut.
Aber woher bekommt man dieses Salz? Ja, hier sitzt sie vor dem Monitor. Lassen Sie ihn zwei oder drei zusätzliche Charaktere herausdrücken und sich endlich menschlich anmelden. Läuft eine Katze herum? Nun, lass uns Katze haben. Was ist Katze? Das ist unser geheimes Wort. Wir werden es während der Registrierung an den Server senden und es wird Salz für dieses Wort erzeugen. Und dann wird er uns dieses Salz schicken. Das war's - der Browser hat Salz. Nun das Passwort. Außerdem verschlüsseln wir das Passwort und salzen es mit dem Salz, das der Server gesendet hat.
Jetzt haben wir keinen Helm "12345". Wir senden einen Hash, und da jeder Benutzer sein eigenes Salz hat, ist der Hash anders.
Es scheint, dass Brute-Force jetzt krank wird: Es muss nicht nur zusätzliche Berechnungen durchführen und statt einfacher Zahlen über lange Reihen von Argon-Hashes iterieren, sondern auch jeder Benutzer hat seinen eigenen Hash - jetzt ist es sinnlos, dieselbe Zeichenfolge als Passwort zu versuchen, um sie für alle zu überprüfen Benutzer. Angenommen, drei Benutzer haben dasselbe Kennwort gewählt: 12345. Ihr Hash ist jedoch unterschiedlich. Weil jeder ein anderes Salz hat.
- Der Browser sollte den Kennwort-Hash mit dem Salt berechnen, das der Server zuvor gesendet hat. Es sollte einen Hash senden, nicht das Passwort selbst.
- Der Server sendet Salt mit einem geheimen Wort, das nur dem Benutzer bekannt ist. Es kann einfach sein. Zum Beispiel - "Katze".
- Jeder Benutzer sollte sein eigenes Salz haben.
- Zwei Benutzer, die dasselbe geheime Wort gewählt haben, müssen ein anderes Salz haben.
- Der Server muss nicht melden, ob das richtige geheime Wort verwendet wurde und ob das Salt für diesen Benutzer korrekt ist. Andernfalls werden zwei einfache Passwörter anstelle von einem Brute-Force-Verfahren verwendet.
- Wenn der Benutzer das geheime Wort ändert, ändert sich auch das Salz.
Das heißt, um sein einfaches Passwort zu schützen, muss der Benutzer ein anderes sehr einfaches Wort finden. Er gibt dieses Wort überall dort ein, wo er authentifiziert werden möchte, und dann muss nur das Passwort eingegeben werden. Bis er die Kekse löscht.
- ging zur Seite
- Login und geheimes Wort eingegeben
- eingegebenes Passwort
- bereit
Das Passwort und das geheime Wort können sehr einfach sein. Ein oder zwei Zeichen. Zum Beispiel ist das Passwort 12345 und das geheime Wort 42. Und wenn jemand anderes das geheime Wort 42 findet, ist es nicht beängstigend.
Wie es funktioniert. Schritt für Schritt Konzept
Wir haben folgende Elemente:
- Webserver
- Datenbank- und Benutzertabelle:
- Anmeldung
- password_hash
- salt_unique_for_each_user
- salt_for_password
- Browser des Benutzers
- Hacker-Browser
- Anmelde- und Registrierungsseiten auf der Website
- Skript, das das Übermittlungsereignis für das Anmeldeformular abfängt
Als nächstes benötigen wir zwei verschiedene Algorithmen, die sogar auf einem Verschlüsselungssystem implementiert werden können, einfach mit unterschiedlichen Parametern:
- ALG1 ist ein asymmetrischer Verschlüsselungsalgorithmus, der aus einem String und Salt einen Hash generiert. ALG1 (str, Salz) = Hash1. Dieser Algorithmus wird nur auf dem Server verwendet.
- ALG2 ist ein asymmetrischer Verschlüsselungsalgorithmus, der aus einem String und einem Salt einen Hash generiert. ALG2 (str, Salz) = Hash2. Dieser Algorithmus wird öffentlich verwendet und sollte auf dem Client implementiert werden können (in unserem Beispiel in Javascript).
Außerdem benötigen wir zwei einfachere Algorithmen:
- ALG_SALT ist ein Algorithmus, der ein zufälliges Salz als Zeichenfolge berechnet. ALG_SALT () = Salz. Dieser Algorithmus wird nur auf dem Server verwendet.
- ALG_PASS ist ein Algorithmus, der ein zufälliges einfaches Passwort generiert. ALG_PASS () = bestanden. Dieser Algorithmus wird nur auf dem Server verwendet.
Ereignisse Schritt für Schritt
- Der Benutzer wechselt zur Registrierungsseite, da er noch kein Login hat.
- Der Server zeigt ein Formular mit zwei Feldern an: Login + einfaches geheimes Wort.
- Benutzer wählt Login - Alice
- Der Benutzer wählt das geheime Wort - Katze
- Der Benutzer klickt auf die Schaltfläche Senden .
Der Server überprüft und stellt sicher, dass die Benutzer-Alice nicht in der Datenbank vorhanden ist.
Der Server berechnet folgende Werte:
$salt_unique_for_each_user = ALG_SALT(); // "saltsalt"
$salt_for_password = ALG1("cat", $salt_unique_for_each_user); // "$argon2id$v=19$m=16,t=2,p=1$c2FsdHNhbHQ$jX94laSi6vo9AhS+bHwbkg"
$user_simple_password = ALG_PASS(); // "12345"
$user_simple_password_hashed = ALG2($user_simple_password , $salt_for_password); // "$argon2id$v=19$m=16,t=2,p=1$JGFyZ29uMmlkJHY9MTkkbT0xNix0PTIscD0xJGMyRnNkSE5oYkhRJGpYOTRsYVNpNnZvOUFoUytiSHdia2c$b+6ROJVsZ62UXA7hEAg0AQ"
Der Server erstellt einen Datensatz in der Benutzertabelle und speichert die Daten:
INSERT INTO `users`
(
login,
password_hashed,
salt_unique_for_each_user,
salt_for_password
)
VALUES
(
"alice",
"$argon2id$v=19$m=16,t=2,p=1$JGFyZ29uMmlkJHY9MTkkbT0xNix0PTIscD0xJGMyRnNkSE5oYkhRJGpYOTRsYVNpNnZvOUFoUytiSHdia2c$b+6ROJVsZ62UXA7hEAg0AQ",
"saltsalt",
"$argon2id$v=19$m=16,t=2,p=1$c2FsdHNhbHQ$jX94laSi6vo9AhS+bHwbkg"
).
Der Server zeigt dem Benutzer eine Registrierungserfolgsseite mit der Meldung: „Benutzer Alice wurde erfolgreich erstellt. Verwenden Sie das temporäre Passwort 12345, um sich anzumelden. "
Der Benutzer ruft glücklich: "Hurra, ich habe mich auf der Website unter dem Spitznamen Alice registriert und sie haben mir das Passwort 12345 gegeben. Was für ein lustiges und einfaches Passwort!" Aber die Wohnung des Benutzers ist sehr schlecht schallisoliert, und sein Hacker-Nachbar hat alles gehört.
- Der Hacker schiebt die Website-Adresse in seinen Browser.
- Der Browser des Hackers sendet leere Cookies.
- Der Server überprüft die Anforderung des Hackers, um festzustellen, ob ein "Salz" -Cookie vorhanden ist. Findet sie nicht.
- Bevor der Hacker den gestohlenen Benutzernamen und das gestohlene Passwort sendet, muss der Browser das Salt kennen, um das Passwort damit zu verschlüsseln.
- Der Browser des Hackers speichert das Salz noch nicht im "Salz" -Keks.
- Der Server sendet ein Anmeldeformular mit zwei Feldern: Login + geheimes Wort, damit der Benutzer das Salz erhalten kann.
Der Hacker ist verwirrt. Lassen wir ihn jetzt.
- Der Benutzer kehrt zur Anmeldeseite zurück.
- Der Browser des Benutzers sendet leere Cookies.
- Der Server überprüft die Anforderung des Benutzers, um festzustellen, ob ein "Salt" -Cookie vorhanden ist. Findet sie nicht.
- Bevor der Benutzer einen Benutzernamen und ein Passwort sendet, muss der Browser das Salt kennen, um das Passwort damit zu verschlüsseln.
- Der Browser des Benutzers speichert das Salz noch nicht im "Salz" -Keks.
- Der Server sendet ein Anmeldeformular mit zwei Feldern: Login + geheimes Wort , damit der Benutzer das Salz erhalten kann.
- Der Benutzer gibt Login - Alice , Secret - Cat ein und klickt auf die Schaltfläche " Senden ".
Der Server empfängt die Anfrage und sieht, dass anstelle eines Passworts ein geheimes Wort gesendet wurde.
- — alice `salt_unique_for_each_user` -> $db_salt_unique_for_each_user `salt_for_password -> $db_salt_for_password`.
- , . : $salt_for_password = ALG1(«cat», $db_salt_unique_for_each_user).
- $salt_for_password . . 12345, , . — ` salt = $db_salt_for_password`. : ` login = «alice»`.
Erläuterung : Der Server benachrichtigt in keiner Weise, welches Salt gesendet wurde - korrekt oder nicht. Das Ergebnis seiner Verwendung wird klar, wenn sie versuchen, sich mit dem richtigen Benutzernamen und Passwort anzumelden.
- Der Benutzer erhält eine Serverantwort. Die Seite wird entweder neu geladen oder ändert sich sofort dynamisch.
- Der Browser des Benutzers sendet Cookies: login = alice , salt = "$ argon2id $ v = 19 $ m = 16, t = 2, p = 1 $ c2FsdHNhbHQ $ jX94laSi6vo9AhS + bHwbkg" .
- Der Server überprüft die Anforderung des Benutzers, um festzustellen, ob ein "Salt" -Cookie vorhanden ist. Findet sie.
- Der Browser verfügt bereits über Salt, um das Passwort zu verschlüsseln.
- Der Server sendet ein Anmeldeformular mit zwei Feldern: Login (hat bereits den Wert Alice ) + Passwort.
- Der Benutzer gibt sein einfaches Passwort 12345 ein und klickt auf die Schaltfläche " Senden ".
- Der Browser fängt das Ereignis onSubmit ab .
- Berechnet $ password_hashed = ALG2 ("12345", "$ argon2id $ v = 19 $ m = 16, t = 2, p = 1 $ c2FsdHNhbHQ $ jX94laSi6vo9AhS + bHwbkg").
- Sendet die Daten "alice" / $ argon2id $ v = 19 $ m = 16, t = 2, p = 1 $
Der Server erhält eine Authentifizierungsanforderung:
- Login + Passwort Daten: "alice" / $ password_hashed
- Geht zur Datenbank und erhält den Wert ` password_hashed` -> $ db_password_hashed.
- Vergleicht $ db_password_hashed === $ password_hashed?
- Hashes stimmen überein, Autorisierung ist erfolgreich.
Hinweis: In meinem Beispiel vergleicht der Server die Hashes direkt. Sie können jedoch keine Zeichenfolgen in der Datenbank speichern, die tatsächlich bereits Kennwörter sind. Sie können gestohlen und dann in Form eines Login-Passworts verwendet werden. Daher müssen Sie Hashes hashen - egal wie seltsam es klingt. Dies bedeutet, dass Sie ein drittes Salz benötigen. Es sollte jedoch nicht in der Datenbank, sondern in der Umgebungsvariablen gespeichert werden. Dies sind jedoch bereits Implementierungsdetails, die ich der Einfachheit halber weggelassen habe.
In der Zwischenzeit beschließt unser Hacker, dieses seltsame Anmeldeformular zu testen:
- Der Hacker gibt Login- Alice , Secret- Dog ein und klickt auf die Schaltfläche " Senden ".
- Der Server empfängt eine Hacker-Anfrage und sieht, dass anstelle eines Passworts ein geheimes Wort gesendet wurde.
- — alice `salt_unique_for_each_user` -> $db_salt_unique_for_each_user `salt_for_password` -> $salt_for_password.
- , , : $result_fake_salt = ALG1(«dog», $db_salt_unique_for_each_user). , .
Der Server sendet den berechneten Salzwert an den Browser des Benutzers zurück. Die Überschriften geben an - `set cookie salt = $ result_fake_salt`. Das Login wird ebenfalls gespeichert: `set the cookie login =" alice "`.
Erläuterung : Um dem Hacker bei der harten Arbeit zu helfen, sendet ihm der Server Salz. Es ist jedoch unmöglich, von außen festzustellen, ob das geheime Wort richtig war oder nicht.
- Der Hacker erhält die Antwort des Servers. Die Seite wird entweder neu geladen oder ändert sich sofort dynamisch.
- Der Browser des Hackers sendet Cookies: login = alice , salt = $ result_fake_salt .
- Der Server überprüft die Anforderung des Benutzers, um festzustellen, ob ein "Salt" -Cookie vorhanden ist. Findet sie.
- Der Browser des Hackers verfügt bereits über Salt, um das Passwort zu verschlüsseln.
- : ( alice) + .
- 12345 "".
- onSubmit.
- $password_hashed = ALG2(«12345», $result_fake_salt).
- «alice»/$password_hashed.
Der Server erhält eine Authentifizierungsanforderung - "alice" / $ password_hashed.
Geht zur Datenbank und erhält den Wert `password_hashed` -> $ db_password_hashed.
Vergleicht: $ password_hashed === $ db_password_hashed? Nee.
Die Hashes dieser anfangs identischen Passwörter stimmen nicht überein. Weil sie auf unterschiedliche Weise gesalzen wurden.
Der Hacker gibt nicht auf und registriert einen anderen Benutzer auf der Website.
Ganz zufällig gibt er das gleiche geheime Wort ein wie der Benutzer hinter der Wandkatze .
Der Hacker erhält ein gültiges Kennwort für das neue Konto und versucht, es in das Hashing-Skript zu ersetzen.
Glücklicherweise verwendete die Passwort-Salzgenerierung ein zweites Salz (`salt_unique_for_each_user`), das für jeden Benutzer auf eine neue Weise generiert wird. So haben verschiedene Benutzer, selbst mit denselben Passwörtern und vor allem geheimen Wörtern, unterschiedliche Salze. Und das Salz des Benutzers mit demselben geheimen Wort stimmt nicht mit dem Salz eines anderen überein. Und passende Passwörter sind auch kein Problem.
Nun zur Komplikation von Brute-Force-Passwörtern in einem Wörterbuch. Wenn wir ALG2 ändern, das sowohl für den Server als auch für den Client üblich ist, und es mühsam machen, wird die Suche nach dem Hacker ernsthaft erschwert. Ich möchte Sie daran erinnern, dass bei ALG2 ein Kennwort-Hash abgerufen wird, der an den Server gesendet wird. Auf dem Server wurde dieser Hash bereits berechnet und in der Datenbank gespeichert:
- Der Server führt den ALG2-Vorgang nur einmal aus, wenn ein Kennwort in die Datenbank geschrieben oder das Kennwort in ein neues geändert wird
- Der Client führt den ALG2-Vorgang nur während der Authentifizierung aus (was nicht mit der Autorisierung verwechselt werden sollte). Angenommen, der Client hat bei der Eingabe des Passworts ein paar Mal einen Fehler gemacht - das ist in Ordnung.
- Der Hacker tut dies die ganze Zeit für jedes Passwort, zu dem er gratulieren kann. Es ist besonders zynisch, dass ein titanischer Aufwand für Passwörter wie 123/1234/12345 aufgewendet wird.
Auf schwachen Maschinen kann der Vorgang viel länger dauern als auf schnellen. Dies kann ein Problem sein. Sie müssen den Algorithmus also nicht komplizieren.
Ich werde die Konzeptbeschreibung mit einem Fass Teer beenden:
- Wenn ein Benutzer versehentlich ein geheimes Wort falsch eingibt, befindet er sich in einer Situation, in der er nicht mit seinem Passwort eingeben kann. Sie müssen das geheime Wort zurücksetzen (in unserem Fall Cookies löschen) und die Anfrage erneut senden. Dies kann transparent durch Drücken einer Taste implementiert werden, aber vorher muss der Benutzer raten. Kann bei 5 falschen Anmeldeversuchen zum Zurücksetzen gezwungen werden.
- Zwei Benutzer am selben Computer müssen sich ständig gegenseitig das Salz entleeren.
- Zwei verschiedene Computer erhalten das gleiche Passwort Salt
- Wenn das Salt auf dem Server über einen Computer geändert wird, weiß der andere Computer mit dem alten Salt nicht, dass es geändert werden muss
- Sie können Salz von Ihrem Computer stehlen und damit einen sehr schnellen Angriff auf Ihr Konto ausführen, da Sie wissen, dass das Kennwort sehr einfach ist.
... und ein Löffel Honig:
- . , "cat" , "termorectal" — . , . , . , .
- . `salt_for_password` , , , . .