Frage:
Gibt es eine Möglichkeit, meiner Benutzerauthentifizierung gesalzenes Hashing hinzuzufügen, ohne meinen früheren Anmeldeserver zu beschädigen?
Ben
2019-12-02 17:11:14 UTC
view on stackexchange narkive permalink

Das folgende Szenario wird angezeigt:

Ich habe eine MySQL-Datenbank mit einer Benutzertabelle. Die Tabelle enthält zwei Felder: Benutzername und Passwort . Das Kennwort wird als ungesalzener Hash gespeichert.

Eine über 15 Jahre alte Anwendung verwendet diese Datenbank, um den Zugriff auf ihre Dienste zu authentifizieren. Der Zugriff ist nur intern möglich.

Unser Team hat die Aufgabe, diese Dienste zu modernisieren, indem es eine neue Anwendung anbietet, die den Best Practices und Erkenntnissen der letzten 15 Jahre (und möglicherweise mehr, die in der ursprünglichen Anwendung ignoriert wurden) folgt. Auf diese Anwendung muss über das weite Internet zugegriffen werden können.

Wir sollten die aktuelle Datenbank für Authentifizierungszwecke wiederverwenden, damit beide Anwendungen parallel auf derselben zugrunde liegenden Authentifizierungsdatenbank ausgeführt werden können.

Ich habe einige Sicherheitsbedenken geäußert, da es bei dieser Anwendung um den Umgang mit persönlichen Daten meiner Mitarbeiter und mir geht.

Wir haben beschlossen, dass ein Teil unserer Modernisierung darin besteht, dass Kennwortrichtlinien eingerichtet und Kennwörter sowohl gesalzen als auch gespeichert werden und gepfeffert.

Dies bedeutet, dass unsere Datenbanktabelle ein drittes Feld salt erhalten würde und das Feld password jetzt unseren gesalzenen und gepfefferten Hash speichert.

Das Problem hierbei ist, dass dadurch die Authentifizierung in unserer alten Anwendung unterbrochen wird. Da der Code sehr alt ist und wir nicht einmal mehr einen funktionierenden Compiler dafür haben, kommt das Ändern des Codes der ursprünglichen Anwendung nicht in Frage.

Meine Frage lautet daher:

  • Gibt es eine sichere Möglichkeit, unserer Authentifizierungsdatenbank Salz (und Pfeffer) hinzuzufügen, während die alte Anwendung weiterhin Benutzer authentifizieren kann? Beachten Sie, dass die alte Anwendung zwar von Natur aus unsicher ist, aber außerhalb unseres Intranets nicht zugänglich ist , die neue Anwendung jedoch.
Können Sie Ihre Frage bearbeiten und angeben, wie die andere Anwendung auf die Datenbank zugreift, um Benutzer zu authentifizieren?Ist es über eine direkte Abfrage für die Tabelle, eine Abfrage an eine Ansicht oder die Ausführung einer gespeicherten Prozedur?
@Freiheit Ich würde es gerne tun, aber das weiß ich ehrlich gesagt nicht.Ich habe nie Zugriff auf die Anwendung erhalten.Ich kann versuchen herumzufragen.
@Ben spielt es eine Rolle, welche Version des DB-Servers Sie verwenden, oder ist es nur der Objektname und das Schema, die wichtig sind?
Wahrscheinlich nicht klug genug für eine eigene Antwort: Beim Anmelden können Sie versuchen, auf dem neuen Weg zu authentifizieren, wenn dies fehlschlägt, versuchen Sie, auf dem alten Weg zu authentifizieren.Drücken Sie die Benutzer langsam dazu, ihre alten Passwörter auf die neue Weise neu zu registrieren.Sie können den Salt-Hash auch abrufen und am Ende des Passwort-Hashs in der Datenbank hinzufügen ("pwd" + "newhash") und sich beim Login dagegen authentifizieren.
@Frank war es erst vor 2 Stunden wichtig, als entschieden wurde, dass es sich um eine MySQL-Datenbank handelt (wie zuvor).Ich habe die Frage entsprechend aktualisiert.
@Ben Sie sollten keinen Zugriff auf die Anwendung benötigen, um herauszufinden, welche Abfragen ausgeführt werden, da Sie die Datenbank steuern.Lesen Sie, wie Sie die Abfrageprotokollierung oder -überwachung in MySQL aktivieren. Auf diese Weise können Sie beobachten, was die Anwendung tut, ohne Zugriff auf die Anwendungsquelle zu haben.
Gibt es einen Grund, warum Sie nicht einfach zwei separate "Passwort" -Felder haben können?Eine, die die schwach gehashte Version speichert, die ausschließlich vom alten internen System verwendet wird, und eine, die eine sichere Version speichert, die ausschließlich vom neuen öffentlichen System verwendet wird?
@DarrenH oder vielleicht nur eine BIT-Spalte wie UseOldHash?
Haben Sie etwas wie Sie beschrieben - 1) neue Spalte in die Datenbank einführen, um neue Passwörter zu kennzeichnen.Ändern Sie den Anmeldecode, um das Kennwort bei der ersten erfolgreichen Anmeldung zu ändern (damit Sie das Kennwort nicht gehasht haben). Verwenden Sie die neue gesalzene Methode und speichern Sie das Kennwort für den Benutzer. Setzen Sie das Flag, dass für diese ein neuer gesalzener Kennwort-Hash ausgeführt wurde
Ist es Ihre Anforderung, die alte Anwendung ohne Codeänderungen funktionsfähig zu halten?Wenn dies der Fall ist, können Sie die Benutzertabelle nicht ändern, ohne die alte Anwendung zu beschädigen, da für die alte Anwendung ein ungesalzenes Kennwort erforderlich ist.Wenn Sie die alte Anwendung ändern können und die Benutzer ihre Kennwörter weiterhin verwenden müssen, ohne sie ändern zu müssen, können Sie sich bei Hash (salt + Hash (Kennwort)) anstelle von Hash (salt + Kennwort) authentifizieren, wie Sie dies sindnicht weniger sicher und Sie können sie berechnen, ohne das ursprüngliche Passwort zu kennen.
Neun antworten:
Anders
2019-12-02 19:22:16 UTC
view on stackexchange narkive permalink

Sie haben hier widersprüchliche Anforderungen. Die Kompatibilitätsanforderungen zwingen Sie dazu, die alten Hashes beizubehalten. Die Sicherheitsanforderungen zwingen Sie, sie fallen zu lassen. Hier müssen Sie entscheiden, welche Anforderungen erfüllt werden sollen.

Wenn Sie die Abwärtskompatibilität beibehalten möchten, versuchen Sie, das Beste aus einer schlechten Situation herauszuholen:

  • Der alte und der neue Hash sollten in verschiedenen Tabellen gespeichert werden, und der von der Webanwendung verwendete Datenbankbenutzer sollte keinen Lesezugriff auf den alten Hash haben. Verwenden Sie hierfür Tabellen- und / oder Spaltenberechtigungen.
  • Wenn Sie die alte Anwendung nicht mehr benötigen, löschen Sie die Tabelle mit dem alten Hash. Ashley Madison ist zu diesem Zeitpunkt bekanntermaßen gescheitert - sie haben ein Upgrade auf bcrypt durchgeführt und dann aus irgendeinem idiotischen Grund die alten MD5-Hashes in der Datenbank herumliegen lassen. Als die Datenbank durchgesickert ist, hat diese ausgefallene Verschlüsselung nicht viel geholfen ...

Oder alternativ, wenn Sie keine Angst haben, ein bisschen Chaos zu verursachen:

  • Lass die alten Hashes fallen. Fügen Sie in der neuen Anwendung die Option "Temporäres Kennwort für alte Anwendung erstellen" hinzu. Sie erhalten ein langes, zufälliges Passwort, das auf die alte Weise gehasht und nur X Minuten in der Datenbank gespeichert wird. Der Benutzer kann sich dann bei der alten Anwendung anmelden, und das Kennwort wird automatisch gelöscht.
Ich habe die akzeptierte Antwort darauf geändert, da sie Aufschluss darüber gibt, dass es Möglichkeiten gibt, das Problem zu umgehen - nur keine perfekte.Aber ich denke, es gibt immer einen Kompromiss, mit dem wir leben müssen.Ich würde gerne mehrere Antworten akzeptieren, die Aufschluss über mögliche Lösungen geben (wie die Antwort von Brian) oder gezeigt haben, dass es keinen "perfekten sicheren Weg" wie den von mti2935 gibt, aber da ich diesen hier nicht denken kannist der wichtigste Imbiss - in Kombination mit all den anderen tollen Antworten.
@Ben Respektlos nicht zustimmen - Sie können dies leicht mit Hash (Hash + Salt) und einer Tabellenansicht / Triggern lösen.Obwohl ich hinzufügen würde, ist das Problem wahrscheinlich organisatorisch.Ich bin mir nicht sicher, warum Sie dieselbe Auth-Datenbank für eine interne LoB-App verwenden möchten, die eine öffentlich zugängliche App steuert.
Eine alternative Möglichkeit bestand darin, das erste Zeichen des gespeicherten Passworts zu erkennen.Wenn es ein "$" war, wusste ich, dass ich [`password_verify ()`] verwenden sollte (https://www.php.net/manual/en/function.password-verify.php).Ansonsten war es ein MD5-Passwort, und ich musste das Passwort nur erneut hashen, nachdem ich bestätigt hatte, dass der MD5-Hash identisch ist, und in der Datenbank speichern.Dadurch wird der MD5 entfernt und Ihr makelloser neuer Hash mit 0 Usability-Problemen bleibt erhalten.In meinem Fall habe ich dieses erneute Hashing beim Anmelden durchgeführt.
@IsmaelMiguel Die alte Anwendung kann die neuen Kennwörter nicht verarbeiten. Sobald ein Kennwort aktualisiert wurde, kann der Benutzer die alte Anwendung nicht mehr verwenden.
@Anders Oh, wenn die Kompatibilität mit der alten beibehalten werden muss, dann ja.Es ist eine gute Idee, das Nur-Lese-Lesen für die alte Tabelle zu erzwingen und die Benutzer zu zwingen, die neue Tabelle zu verwenden, um die Sicherheit zu erhöhen.
Brian
2019-12-03 02:53:15 UTC
view on stackexchange narkive permalink

Gibt es eine sichere Möglichkeit, unserer Authentifizierungsdatenbank Salz (und Pfeffer) hinzuzufügen, während die Fähigkeit der alten Anwendung zur Authentifizierung von Benutzern erhalten bleibt?

Ja, dies ist möglich. Im Folgenden finden Sie allgemeine Implementierungsanweisungen. Die grundlegende Technik besteht darin, alle Kennwörter zu hashen und dann die Verbindung zwischen dem Client und dem Legacy-Server mit MITM durchzuführen, um das nicht gehashte Passwort durch ein Hash-Passwort zu ersetzen. Beachten Sie, dass Sie einen Roll-out-Plan erstellen müssen. Wenn Sie Schritt 1 in der Produktion blind ausführen, wird alles kaputt gehen.

Schritt 1: Alle vorhandenen Kennwörter salzen und das Salz dann irgendwo speichern. Überschreiben Sie das Kennwortfeld der Legacy-Datenbank mit dem gesalzenen Kennwort.

Schritt 2: Erstellen Sie einen Shim. Der Shim akzeptiert identische Parameter wie die Legacy-APIs.
Wenn die Legacy-API wie folgt implementiert ist:

  LegacyDoStuff (Benutzername, Kennwort, Argument) {if (! VerifyCredentials (Benutzername, Passwort)) return AuthenticationError (); Ergebnis = DoStuff (Argument); Ergebnis zurückgeben;}  

Die neue API wird implementiert als:

  NewDoStuff (Benutzername, Passwort, Argument) {hashedpassword = DoHash (Passwort + getSalt (Benutzername) )) LegacyDoStuff (Benutzername, Hash-Passwort, Argument) zurückgeben;}  

Schritt 3: Richten Sie den Legacy-Client auf den Shim anstatt auf den Hauptserver (oder gleichwertig) Verschieben Sie den Legacy-Server auf eine neue IP / DNS-Adresse und setzen Sie die Unterlegscheibe auf die alte IP / DNS-Adresse.

Mit diesem Ansatz können Sie die Interna des Legacy-Codes als Black Box behandeln, aber es erfordert, dass Sie sich der öffentlichen Oberfläche des Legacy-Codes bewusst sind, da Ihr Shim Anforderungen / Antworten zwischen dem Client und dem Legacy-Server senden muss.

Bei diesem Ansatz wird im Gegensatz zu den in anderen Antworten beschriebenen Ansätzen das Speichern des alten Kennworts vollständig vermieden. Dieser Ansatz ist jedoch viel schwieriger durchzuführen und führt mit größerer Wahrscheinlichkeit zu Fehlern.

Wie funktioniert Schritt 1, wenn die aktuelle Datenbank Hashes der ursprünglichen Kennwörter und nicht der ursprünglichen Kennwörter selbst enthält?Es gibt keine Möglichkeit, "Hash (bestehendes Passwort + Salz)" zu generieren, ohne das vorhandene Passwort zu kennen.
Wenn es sich um eine alte Quick-Hashing-Funktion handelt, können sie diese wahrscheinlich mit wenig Aufwand knacken.Alternativ können alle Benutzer ihre Kennwörter neu festlegen.
Aus rein technischer Sicht liebe ich diese Idee.Und ja, tatsächlich erfüllt es im Grunde alle Anforderungen, die wir haben.Und trotzdem bezweifle ich, dass mein Chef uns dies jemals tun lassen würde, wenn wir ihm erklären, dass wir unser eigenes System MITM wollen ... Wirklich großartige Antwort, obwohl imho!
@Ben Dies ist in der Tat eine wirklich clevere Idee.Wenn Sie es "Proxy" anstelle von "MITM" nennen, ist Ihr Chef vielleicht eher geneigt zuzustimmen?
@SawyerKnoblich Angenommen, die alte Hash-Funktion war "Hash (Passwort)", dann kann die neue Funktion "pbkdf2 (sha1, Hash (Passwort), Salt, 1000 * 1000)" sein - dh die endgültige Hash-Funktion ist eine zweistufige Funktion.
Ich stimme Anders zu, dass es eine bessere Möglichkeit ist, es dem Management zu präsentieren, wenn man es als Proxy (oder genauer gesagt als Reverse Proxy) bezeichnet.Ich habe den Begriff MITM absichtlich verwendet, weil ich mich wie die Sicherheit fühlte. Das SE-Publikum würde den Ansatz schneller verstehen, wenn ich ihn mit diesem Begriff erläutern würde.Abgesehen davon könnte man es auch einfach eine Unterlegscheibe nennen.Die Tatsache, dass der Shim über einen Reverse-Proxy implementiert wird, ist ein Implementierungsdetail (und eines, das Sie möglicherweise sofort vermeiden könnten, wenn der Legacy-Code als Bibliothek und nicht als Webanwendung verwendet werden kann).
Beachten Sie, dass das alte Passwort _hashed, aber ungesalzen_ ist. Ich denke, der tatsächlich in der DB gespeicherte neue Passwort-Hash muss "OldHash (NewHash ($ salt + OldHash ($ password))" sein - das innerste "OldHash ($ password")) `sind die zuvor gespeicherten Daten und der äußerste` OldHash (...) `Aufruf ist das, was die unveränderten` VerifyCredentials` berechnen.Oder habe ich etwas falsch verstanden?
Entschuldigung, ich verstehe das nicht.Was genau meinst du mit "* Legacy API *"?Die API der Datenbank zur Legacy-Anwendung?Die API / das Frontend der Legacy-Anwendung (könnte HTML für Benutzer sein, könnte in einer Desktop-Anwendung überhaupt nichts sein)?Etwas anderes?Wenn ich das OP richtig verstanden hätte, wären sowohl die LegacyDoStuff-Funktion als auch ihr Aufrufer nicht veränderbar.
@Bergi Ich habe verstanden, dass es "irgendwo zwischen dem Benutzer und der alten Anwendung" bedeutet.Bei einer Webanwendung akzeptiert der Shim die Eingabe aus dem Anmeldeformular, bearbeitet den Kennwortwert und sendet ihn an die reale Anwendung.
@IMSoP Ah, das würde Sinn machen, danke!
mti2935
2019-12-02 17:52:13 UTC
view on stackexchange narkive permalink

Gibt es eine sichere Möglichkeit, unserer Authentifizierungsdatenbank Salz (und Pfeffer) hinzuzufügen, während die alte Anwendung weiterhin Benutzer authentifizieren kann?

Nein. Der Grund für das Versalzen und Hashing von Passwörtern besteht darin, dass die Angreifer-Passwörter für den Angreifer nicht zugänglich sind, wenn die Benutzerdatenbank gehackt / durchgesickert / kompromittiert wird (siehe Was bringt das Hashing von Passwörtern?). In der von Ihnen beschriebenen Lösung werden die Kennwörter der Benutzer weiterhin in der Benutzerdatenbank in einer benachbarten Spalte im Klartext gespeichert. Dies macht den Zweck des Salzens und Hashens von Passwörtern vollständig zunichte.

Das heißt, da wir nur versuchen, einen potenziellen Datenbereich weniger effektiv zu machen, öffnen wir uns einfach einer viel größeren Welt der Verletzungen, indem wir die Daten jetzt auch über das offene Internet anstatt nur intern zugänglich machen und die Chance für einen solchen Verstoß nutzenpassieren in erster Linie nur viel wahrscheinlicher, richtig?Ich sehe nicht ein, dass dies alles andere als eine massive Sicherheitskatastrophe ist, die gerade stattfinden wird ...
Genau.Ich denke, Ihre Organisation muss ernsthaft darüber nachdenken, die Legacy-Anwendung so zu aktualisieren oder zu ersetzen, dass sie modernen Sicherheitsstandards entspricht.Wenn dies in naher Zukunft nicht möglich ist, sollten Sie zwei separate Datenbanken verwenden (eine für die interne Legacy-Anwendung mit im Klartext gespeicherten Kennwörtern und eine weitere separate Datenbank für die neue öffentlich zugängliche Anwendung mit gesalzenen Kennwörternund Hash) und Ausführen eines Prozesses, der die Daten zwischen den beiden Datenbanken synchronisiert.
Die Operation sagt nicht, dass es ein Klartext-Passwort gibt.
@Frank: Ungesalzen mit schwachem Hash ist in jeder Hinsicht Klartext.
@R .. stimmte zu, aber es ändert die Parameter des Problems.Wir wissen jetzt, dass das Problem gelöst werden kann, da beim Zurücksetzen des Passworts kein Klartext gespeichert wird.Siehe meine Antwort unten für eine Lösung
Was ist mit der Migration von "Hash (Plain)" zu "Hash (Hash (Plain), Salt)"?Nur aus Interesse, da dies die Legacy-Anwendung beschädigen würde.
@NumLock Ja, das würde funktionieren, das ist die Antwort unten.Ich bin mir nicht sicher, warum dies als akzeptierte Antwort markiert ist, da es verschiedene Möglichkeiten gibt, dies umzusetzen.
Es ist wahr, dass Sie das Problem nicht beseitigen können, während die alte App ausgeführt wird, aber es klingt so, als ob geplant ist, die neue App aufzurufen, sie parallel auszuführen, bis die Feature-Parität erreicht ist, und dann die neue App zu beenden.In diesem Fall könnte die Antwort besser als "Ja, irgendwann" formuliert werden.Wenn ich falsch liege und beide auf unbestimmte Zeit ausgeführt werden sollen, ist "Nein" die absolut richtige Antwort.
Douglas Leeder
2019-12-02 17:48:17 UTC
view on stackexchange narkive permalink

Natürlich muss die aktuelle Tabelle erhalten bleiben, damit die alte Anwendung funktionieren kann.

Fügen Sie möglicherweise eine neue Tabelle mit gesalzenen + gepfefferten Hashes hinzu, damit die neue Anwendung sie verwenden kann, und dann:

  • Machen Sie die alte Tabelle für die neue Anwendung unzugänglich!
  • Aktualisieren Sie beide Tabellen, wenn Sie das Kennwort eines Benutzers aktualisieren.
  • Fordern Sie alle Benutzer des neuen Systems auf, ihr Kennwort zu aktualisieren / zurückzusetzen.
  • In der neuen Tabelle kann eine Kopie gespeichert werden Der alte Hash wird zunächst aktualisiert und dann ordnungsgemäß gehasht, wenn der Benutzer sein Kennwort aktualisiert.

Dies setzt voraus, dass das Kennwortkontrollsystem von einem der Inhaltssysteme getrennt ist.

Dies bedeutet, dass eine Sicherheitsanfälligkeit im neuen System nicht auf die alten Hashes zugreifen kann (nach der Migration). Die Datenbank kann eine Sicherheitsanfälligkeit aufweisen, die es den Datenbankanmeldeinformationen des neuen Systems ermöglicht, auf eine Tabelle zuzugreifen, die sie nicht sollte. Dies ist jedoch viel weniger wahrscheinlich als bei Ihrer neuen Anwendung mit einer Sicherheitsanfälligkeit.

Gibt es aus technologischer Sicht, wenn auf die Tabelle für die neue Anwendung nicht zugegriffen werden kann, eine Möglichkeit, den Tabelleninhalt zu verlieren, ohne dass jemand Zugriff auf mein internes Netzwerk erhält?
Nur wenn die Datenbank eine Sicherheitsanfälligkeit aufweist, die es dem Konto des neuen Systems ermöglicht, auf Tabellen zuzugreifen, sollte dies nicht der Fall sein.
Sie könnten eine völlig separate Datenbank verwenden, aber das macht das Passwort-Update-Programm komplizierter.
Okay.So konnten wir zumindest die potenzielle Sicherheitslücke auf einem vergleichsweise ähnlichen Niveau halten wie vor der neuen Anwendung (die wahrscheinlich bereits viel zu hoch ist), indem wir den Zugriff auf alle neuen Sicherheitslücken einschränken.Ich denke das ist etwas.
Hayley
2019-12-03 05:57:55 UTC
view on stackexchange narkive permalink
  1. Fügen Sie zwei neue Spalten hinzu, eine Salt-Spalte und eine neue Hash-Spalte, zunächst null.
  2. Wenn eine Authentifizierungsanforderung eingeht, überprüfen Sie das Salt-Feld.
  3. Wenn das Feld einen Wert hat, gibt es einen neuen Hash, dem Pfeffer und Salz hinzugefügt wurden. Gehen Sie entsprechend vor.
  4. Wenn nicht, handelt es sich um einen Hash im alten Stil. Überprüfen Sie mit dem alten Mechanismus. Vorausgesetzt, es ist erfolgreich, haben Sie jetzt das Klartext-Passwort aus der ursprünglichen Anfrage. Wenn Sie ein Salz generieren und speichern, haben Sie jetzt alles, was Sie zum Berechnen und Speichern eines neuen Hash benötigen. Das Legacy-System weiß nichts davon, daher kann es nur das neue System. (Es wäre besser gewesen, wenn sich kein System damit befassen müsste, aber den Job an die Datenbank selbst delegieren könnte. Das neue System kann, das alte System nicht.)
  5. ol>

    Schließlich auch Jeder hat sich mindestens einmal angemeldet und seine Hashes transparent aktualisiert (es sind keine NULL-Salze mehr in der Tabelle), oder die einzigen, die noch übrig sind, sind diejenigen, die sich überhaupt nicht anmelden.

    Setzen Sie das ungesalzene und Gesalzene Hashes direkt nebeneinander in der Tabelle veranschaulichen nur die Tatsache, dass die Verwendung von Best Practices im neuen System unter Sicherheitsgesichtspunkten weiterhin irrelevant ist, solange das Altsystem weiterhin verwendet wird.

Warum brauchen Sie eine neue Hash-Spalte?
@kevinSpaceyIsKeyserSöze Wir müssen den ungesalzenen Hash beibehalten, damit die alte App ausgeführt wird, und einen gesalzenen Hash (der anders sein wird), damit die neue App sicher ausgeführt werden kann.
Während dies eine Möglichkeit ist, die neuen gesalzenen Hashes zu generieren, besteht eine andere darin, alle vorhandenen Einträge doppelt zu hashen.Beides ist für den Hauptteil dieser Frage nicht besonders relevant, nämlich wie die Legacy-App funktioniert.Der einzige Teil dieser Antwort, der sich mit folgenden Themen befasst, lautet "Neue Spalte erstellen und alte verlassen".
Frank
2019-12-03 05:50:26 UTC
view on stackexchange narkive permalink

Ja, das ist möglich.

Verwenden Sie in der neuen Anwendung einen Hash-of-Hash-Doppel-Hash-Algorithmus, z. B.: Schritt 1: Hash das gesalzene Passwort, Schritt 2: Hash das Hash (kein Salz)

Ansatz 1:

Entwickeln Sie eine einfache eigenständige App, die ein Kennwort verwendet und den gesalzenen Hash eines Benutzerkennworts generiert und anzeigt

Bitten Sie alle internen Benutzer, ihr Kennwort in der alten Anwendung auf die Ausgabe der eigenständigen App zurückzusetzen, und verwenden Sie von nun an bei der Anmeldung den Vorgang der Eingabe des Kennworts in die Standalone-App zum Generieren des Passwort-Hashs, der in den Anmeldebildschirm eingegeben wird. Die Ausgabe könnte in die Zwischenablage generiert werden, um visuelle Hinweise zu vermeiden.

Ansatz 2

Wenn Sie die Datenbank irgendwie verwenden können, führen Sie den Hash von Hash in ein die Datenbank. Machen Sie Schritt 2 zum gesalzenen Hash und speichern Sie nur diesen.

Bearbeiten, um Folgendes zu verdeutlichen: Beispiel: Wenn Sie eine Datenbank verwenden, die benutzerdefinierte Operatoren unterstützt, deklarieren Sie einen benutzerdefinierten Gleichheitsoperator in einer Spalte, in der der newsaltedhash (oldhash) gespeichert ist. als benutzerdefinierter Typ. Wenn die App eine Abfrage nach einer Zeile mit übereinstimmendem Benutzernamen und altem Hash ausführt, führt der benutzerdefinierte Operator einen Newsalted-Hash für den eingehenden Hash aus und führt den Vergleich durch. Das Zurücksetzen des Kennworts erfolgt durch Einfügetrigger.

Zusammenfassung: In beiden Szenarien funktionieren Ihre Apps wie ursprünglich entworfen und der gespeicherte Kennwort-Hash ist ein Hash + Salt-Double-Hash (Pepper optional in beiden Implementierungen hinzugefügt)

Während dies funktioniert, ersetzt es ein schlechtes System durch ein besseres, aber immer noch etwas hackiges und sehr ungewöhnliches.IMHO ist es besser, nur eine saubere Pause zu machen und standardisierte Komponenten wie bcrypt zu verwenden, als erneut zu versuchen, Ihre eigenen zu rollen.
@SteveSether Ich würde voll und ganz zustimmen.Dies widerspricht jedoch dem Geist der Frage.Die ganze Prämisse der Frage ist seltsam.Noch wichtiger ist die Frage, warum eine interne Authentifizierungsdatenbank für Branchen eine öffentlich zugängliche Datenbank antreibt und das Risiko besteht, dass DDoS-Angriffe im Internet auf interne Authentifizierungsdatenbanken ausgesetzt werden.Ja.Eine saubere Pause ist unerlässlich, aber das OP hat nicht klargestellt, warum er sich in dieser sehr unorthodoxen Situation befindet.
Hinweis für andere: "Verwenden von 'Standard'-Komponenten wie bcrypt" sollte nicht als "Verwenden von bcrypt" verstanden werden.In .NET gibt es beispielsweise keine geprüfte sichere Implementierung von bcrypt AFAIK, und es ist besser, die Bibliotheks-Hash-Funktionen aus einer Sekunde zu verwenden.
Ich glaube nicht, dass Sie bcrypt verwenden müssen.Aber ich denke auch nicht, dass "vollständig geprüft" auch absolut notwendig ist.FWIW gibt es eine SO-Frage zu bcrypt auf .net https://stackoverflow.com/questions/873403/net-implementation-of-bcrypt
Dies klingt nach einer Variante von [Brians Antwort] (https://security.stackexchange.com/a/222180/51961), verwendet jedoch die Benutzer, um einen Teil der Arbeit zu erledigen.Beachten Sie, dass Sie nicht nur ein Tool zum Generieren von "gesalzenem Hash" haben können, sondern auch den richtigen gesalzenen Hash mit dem gespeicherten Salt für diesen Benutzer generieren müssen.Außerdem müssen sich die Benutzer ohnehin beim neuen System anmelden können, sodass es wahrscheinlich einfacher ist, Hashes der Form "NewHashFunction ($ salt + $ oldHashValue)" in großen Mengen zu generieren.Sie können dann die alte Tabelle mit "OldHashFunction ($ newHashValue)" in großen Mengen aktualisieren, anstatt die Benutzer dazu zu bringen, ihre Kennwörter zurückzusetzen.
@IMSoP no Brians Antwort ist anders. Er spricht davon, den ursprünglichen Hashing-Algorithmus beizubehalten, aber die Belichtung durch Timeouts zu begrenzen.Abhängig von der Datenbankfunktionalität könnte das oben Genannte ohne zusätzliches Tool perfekt funktionieren. Es hängt nur davon ab, ob die Hash-Gleichheit auf der Ebene von Datenbank abgefangen werden kann oder nicht.
@Frank Huh?Wo sehen Sie etwas über "Timeouts" in der Antwort, die ich verlinkt habe?Es wird dieselbe Grundidee vorgeschlagen: Anstelle von "OldHash ($ password)" speichern Sie "OldHash ($ newPasswordHash)".In Brians Version generiert ein Shim- oder Reverse-Proxy den korrekten Wert für "$ newPasswordHash" und leitet ihn automatisch weiter.In Ihrem Fall führt ein interaktives Tool dies aus und der Benutzer gibt es manuell ein.
@IMSoP oh richtig ja ich habe mir eine andere Antwort angesehen.Trotzdem würde ich sagen, dass die Architektur / das Konzept anders ist
@IMSoP zB nur raten, aber wenn dies Postgres oder Orakel wäre, könnten Sie dies nicht mit einem benutzerdefinierten Operator tun?
@Frank Nein, die Datenbank konnte dies nicht für Sie tun. Sie befindet sich am falschen Ende der Legacy-Hashing-Funktion.
@Frank Vielleicht könnten Sie klarer machen, welcher Wert Ihrer Meinung nach in der Datenbank gespeichert wird und wie er von der Legacy-Anwendung überprüft wird.Soweit ich sehen kann, besteht die einzige Möglichkeit darin, "OldHash ($ newPasswordHash)" zu speichern, da dies von der alten Anwendung berechnet wird.Was, wie ich schon sagte, dies zu einer Variante der anderen Antwort macht - was als solche keine schlechte Sache ist, sondern nur eine Beobachtung, die vielleicht verwendet werden könnte, um sie zu erweitern.
@Bergi hängt das nicht davon ab, wie die App implementiert ist?Beispiel: Wenn die App 1. Hash-Passwort ausführt 2. Fragen Sie nach der Anzahl der Zeilen, in denen Benutzername = X und Passworthash = y. Wenn es sich um Postgres handelt, können Sie einen benutzerdefinierten Operator ausführen, der newpasswordhash (eingehender Hash) ausführt, um mit dem zu vergleichen, was sich darin befindetdie dB, dh newpasswordhash (oldhash)
@IMSoP mit Beispiel bearbeitet
@Frank Ah, OK, ich nahm an, dass dieser Teil mit dem ersten zusammenhängt, aber es ist tatsächlich eine andere und ziemlich geniale Idee.Dies funktioniert nur, wenn die alte Anwendung den Hash in die where-Klausel einer Abfrage einfügt. Dies ist jedoch kein besonders sinnvolles Design (es ist nicht einmal möglich, wenn Sie anfangen, Ihre Hashes zu salzen), aber ziemlich häufig.
@IMSoP Das stimmt, es werden Annahmen über die Art und Weise getroffen, wie der Code entworfen wird, aber ich denke, das Konzept, das ich vermitteln wollte, war im Großen und Ganzen nur diese Intuition, dass Newhash (Oldhash) Hash-of-Hash einige unterschiedliche Ansätze eröffnet.Gut Feel sagt mir, dass es wahrscheinlich andere clevere Methoden gibt, die gespeicherte Prozesse / einfügbare Ansichten usw., .NET T-SQL-Module und dergleichen beinhalten.Wenn die App nur den Passwort-Hash lädt, sobald der Benutzername eingegeben wurde, funktioniert der db-seitige Ansatz nicht.
@Frank Ja, ich denke mit dem Beispiel ist es ein interessanter Vorschlag.Vor diesem Beispiel war es zu vage, um nützlich zu sein, insbesondere weil "newhash (oldhash)" ohnehin häufig als Migrationspfad verwendet wird (weil Sie alle vorhandenen Daten migrieren können, ohne die Klartextkennwörter zu kennen).
@IMSoP Einverstanden.Mir ist jetzt klar, dass bei Stackoverflow die Antworten präzise sein müssen und keine Richtlinien.Ich denke, wenn OP unbedingt diesen Weg gehen muss, sollte er eine Datenbank verwenden, die benutzerdefinierte Operatoren anstelle von MySQL unterstützt, da diese Methode seinen Fall tatsächlich direkt und sauber löst.(Nun, wenn wir sicher wären, dass die App gegen Hash prüft)
IMSoP
2019-12-04 14:59:35 UTC
view on stackexchange narkive permalink

Diese Antwort ist inspiriert von Brians Antwort und Franks Ansatz Nr. 1, die beide im Wesentlichen den neuen gesalzenen Hash als Passwort für die alte Anwendung verwenden. Da eine Anwendung das Salt aus der Datenbank abrufen muss, um den Hash zu generieren, wäre es einfacher und sicherer, wenn diese Anwendung den Benutzer authentifiziert und ein vollständig separates zufälliges Token als Kennwort für das alte System verwendet. P. >

Schritt 1: Wählen Sie eine moderne Passwort-Hashing-Lösung.

Wählen Sie eine gut unterstützte Passwort-Hashing-Bibliothek für die Sprache Ihrer Wahl aus, die das Generieren von sicherem Salt für Sie übernehmen soll. Es wird wahrscheinlich eine einzelne Zeichenfolge ausgegeben, die den Hash, das Salt und andere Parameter enthält, die zur Überprüfung des Kennworts erforderlich sind, sodass Sie in Zukunft schrittweise einen stärkeren Algorithmus einführen können. Verwenden Sie im Fall von PHP beispielsweise die integrierten Kennwort-Hashing-Funktionen.

Erstellen Sie eine neue Spalte in der Datenbank, um diese einzelne Zeichenfolge zu speichern. Eine Möglichkeit, dies zunächst zu füllen, besteht darin, NewHashFunction (OldStoredHash) zu berechnen und dann NewVerifyFunction (NewStoredHash, OldHashFunction (UserEnteredPassword)) auszuführen. Es gibt viele Diskussionen darüber, und es macht keinen Unterschied zum Rest dieser Antwort.

Schritt 2: Leere die alte Passwortspalte

Lösche alle dauerhaft alte unsichere Hashes, aber lassen Sie die Spalte nicht fallen. Zu diesem Zeitpunkt kann sich niemand bei der alten Anwendung anmelden, daher müssen wir das beheben ...

Schritt 3: Erstellen Sie ein Tool, um sich bei der alten Anwendung anzumelden.

Erstellen Sie eine Seite in Ihrer neuen Anwendung (wo der Benutzer bereits authentifiziert ist) oder einer eigenständigen Seite (die den Benutzer mithilfe der neuen Kennwortbibliothek authentifiziert), die Folgendes ausführt:

  • Erzeugt ein langes zufälliges Kennwort
  • Speichert den ungesalzenen Hash dieses zufälligen Passworts in der alten Passwortspalte für den authentifizierten Benutzer
  • Zeigt dem Benutzer entweder das Kennwort zur Eingabe in die alte Anwendung an oder sendet es direkt, um den Benutzer automatisch anzumelden.

Beachten Sie, dass dieses zufällige Kennwort nicht gespeichert werden muss Überall, denn wenn sich der Benutzer erneut anmelden möchte, kann er einfach ein neues generieren.

Schritt 4: Machen Sie es sicherer, indem Sie das Zeitlimit für die Token überschreiten.

Die zufälligen Kennwörter sind Es ist bestimmt viel stärker als die meisten Benutzer, wenn sie keinen Passwort-Manager verwendet hätten. Sie werden jedoch weiterhin ungesalzen gespeichert und verwenden wahrscheinlich einen schnellen Hash. Es besteht auch das Risiko, dass das Passwort irgendwo kopiert wird, wenn es dem Benutzer angezeigt wird. Wir können beide Angriffe erheblich erschweren, indem wir nur die zufälligen Passwörter für einen kurzen Zeitraum gültig haben.

Fügen Sie der Datenbank eine zusätzliche Spalte für das "Ablaufdatum des zufälligen Kennworts" hinzu. Dies kann sehr kurz sein, wenn Sie sich automatisch anmelden, und einige Minuten, wenn der Benutzer das Kennwort selbst eingeben muss. Ein geplanter Job sollte dann einmal pro Minute ausgeführt werden und das alte Kennwortfeld für alle abgelaufenen Zeilen leeren.

Dies ist nicht nur eine hervorragende Antwort, sondern sollte auch als gutes Beispiel dafür dienen, wie scheinbar unüberwindbare Probleme oft nicht offensichtliche Lösungen haben
simon at rcl
2019-12-02 17:25:24 UTC
view on stackexchange narkive permalink

Fügen Sie der Benutzertabelle als Pat des Upgrades eine Spalte hinzu, die angibt, ob das Konto aktualisiert wurde oder nicht. Wenn dies nicht der Fall ist, verwenden Sie den alten Code, um den Hash zu generieren und zu überprüfen. Wenn dies in Ordnung ist, generieren Sie das Salt und den neuen Hash und aktualisieren Sie den Benutzerdatensatz auf den neuen Hash Salt und setzen Sie das Flag Upgraded.

Wenn das Flag Upgraded bei der Anmeldung gesetzt ist, verwenden Sie den neuen Code Um das Salz zu lesen, machen Sie den Hash und überprüfen Sie das.

Während dies offensichtlich funktioniert, um die aktuelle Lösung auf eine neue zu aktualisieren, wird die alte Anmeldefunktion immer noch unterbrochen, sobald ein Konto als "Aktualisiert" markiert ist. Richtig?Wichtig ist, dass auf ein Konto auch nach Änderungen mit der alten Anmeldemethode zugegriffen werden kann.Beide Anwendungen müssen parallel ausgeführt werden, um alte Legacy-Clients zu unterstützen, auf denen die neue Anwendung nicht ausgeführt werden kann (z. B. kein modernes Betriebssystem).
Wenn ich davon ausgehe, dass die alte Site von der neuen getrennt ist, aktualisieren Sie die alte Site nicht - insbesondere, wenn Sie sie nicht ändern möchten.Wenn sie eine gemeinsame Datenbank gemeinsam nutzen, fügen Sie anstelle eines Upgrade-Flags ein AccountVersion-Flag hinzu und setzen Sie die vorhandenen Konten auf 1. Neue Konten wären Version 2 und verfügen auf die neue Weise über Salt und Hash.Jeder kompetente Entwickler sollte in der Lage sein, dies oder Variationen davon zu tun.
Das Problem ist, dass alle Benutzer aktiviert werden sollten, um sich sowohl mit der alten als auch mit der neuen Anwendung anzumelden.Es gibt kein "entweder oder", es ist immer "beides".Auch neu hinzugefügte Benutzer müssen sich in beide Richtungen anmelden können. In meinen Gedanken bedeutet dies, dass der einzige Weg darin besteht, sowohl den ungesalzenen als auch den gesalzenen Hasch zu speichern - und das macht den Zweck völlig zunichte und ich kann die Lösung direkt einfach verschrotten. Wenn wir einfach eine neue Anwendung schreiben würden, könnten Sie mir vertrauen, dass ich niemals eine 15 Jahre alte Datenbank einrichten und etwas Neues erstellen würde ... Es sind leider die Einschränkungen, die mir verbleiben.
Wie gibt der Benutzer an, auf welche Weise er sich anmelden möchte?Dies ist eine sehr unklare Situation: Sie haben die Kontrolle über den Hashing-Prozess und nicht über den Benutzer.Sie müssen sicherstellen, dass der Hashing-Prozess mit dem des gespeicherten Hashs übereinstimmt, nicht mit dem des Benutzers.Sie haben die Kontrolle.Dies sind ziemlich elementare Ideen, wie man den richtigen Prozess auswählt und / oder von einem zum anderen konvertiert.Wenn dies keine Anleitung für eine Lösung gibt, habe ich das Problem überhaupt nicht verstanden - sorry!
Es wird von der von ihnen verwendeten Anwendung angegeben.App A (die Legacy-App) kann nur mit ungesalzenen Hashes arbeiten.Wir haben hier keine Kontrolle - die Anwendung kann nicht mehr geändert werden.App B (die neue App) kann mit allem funktionieren - wir haben hier die Kontrolle, wie zu Recht erwähnt.Ein Benutzer "Peter" muss weiterhin sowohl von App A als auch von App B authentifiziert werden können, um auf dieselben Daten zuzugreifen.Ich glaube nicht, dass Sie etwas missverstanden haben - ich fürchte, die Situation ist von Anfang an völlig unvernünftig ...
Das klingt so, als ob Sie mit Konten der Versionen 1 und 2 gehen und entsprechend hashen sollten.Dies würde keine Änderung an der alten App erfordern, da ohnehin nur v1-Hashes ausgeführt würden.
Ja, das geht in Richtung der obigen Antwort von Douglass Leeder - zwei separate Konten, die irgendwie miteinander verbunden sind, und zusätzliche Einschränkung des Zugriffs auf die relevanten Teile in irgendeiner Weise.Ich denke, das ist das kleinere Übel, mit dem wir leben müssen.
Eigentlich nicht (unbedingt).Ein v1-Konto würde von v1 auf dem alten und dem neuen gehasht.Ein v2-Konto würde von v2 im neuen gehasht und würde sich immer nicht beim alten anmelden.Personen, die Alt und Neu verwenden, hätten vor dem neuen System keine Konten auf dem alten System eingerichtet (sofern sie diese noch nicht haben).
Damon
2019-12-03 22:14:02 UTC
view on stackexchange narkive permalink

Das Speichern gesalzener Passwörter ist soooooooo 1995. Daher sollten Sie (wenn nichts Besseres möglich ist) mindestens einen gesalzenen Hash mit vielen Iterationen des Hash speichern. Dies ist tatsächlich weniger problematisch als Sie denken.

Ein Problem bei diesem Schema ist, dass Sie nicht wissen, wie viele Iterationen ausreichen, und wenn Computer schneller werden, benötigen Sie möglicherweise mehr. Zu viel Hashing ist jedoch sehr teuer ... insbesondere für eine große Benutzerdatenbank. Wie kann man das lösen?

Die häufig angewandte Lösung für diese Frage ist gleichzeitig die Lösung für Ihr primäres Problem.

Um dies zu berücksichtigen Wenn Sie die CPU-Leistung (oder wirklich die GPU-Leistung) erhöhen, fügen Sie eine weitere Spalte mit der Anzahl der Iterationen hinzu. Hin und wieder fügen Sie einem Benutzer eine Iteration hinzu (z. B. 5% zufällige Chance bei jeder Anmeldung). Dies ist sehr wenig Arbeit, da Sie nur einen zusätzlichen Hash ausführen müssen. Aktualisieren Sie sowohl die Anzahl als auch den gespeicherten Hash.

Nun muss erkannt werden, dass ein Hash-Passwort immer noch nur ein Passwort ist. Es ist ein bisschen "unlesbar", aber es ist immer noch nur ein Passwort, sonst nichts. Niemand hindert Sie daran, das zu salzen und es erneut zu hashen. Hasch es sogar oft. Kein Schaden angerichtet.

Wenn Ihre Authentifizierungsschicht eine Zeile aus der Datenbank abruft, in der die Hash-Anzahl Null ist, weiß sie, dass dies ein "alter" Eintrag ist, bei dem das Kennwort nicht gesalzen wurde (dies ist der Fall) null zusätzliche Hash-Runden). Also ... salzen Sie es, hacken Sie es tausendmal und speichern Sie 1000 für die Hash-Anzahl sowie den gesalzenen Hash. Fertig.

Die Anmeldeprozedur wäre also ungefähr so ​​(im Pseudocode):

  hash_entered = H (password_entered); [hash, count] = sql_query (SELECT WHERE Benutzername = blah); if (count == 0) {login_success = compare (hash_entered, hash); für (i = 0; i < 1000; ++ i) Hash = H (Hash); sql_query (UPDATE Hash = Hash, Anzahl = 1000); return login_success;} else {für (i = 0; i < count; ++ i) hash_entered = H (hash_entered);
login_success = compare (hash_entered, hash); if (zufällig (100) < = 5) {Hash = H (Hash); sql_query (UPDATE Hash = Hash, Anzahl = Anzahl + 1); } return login_success;}  
Während einige dieser Antworten vernünftige allgemeine Ratschläge sind, geht sie nicht auf die spezifische Situation in dieser Frage ein, wie die alte Anwendung funktionsfähig bleibt.
Was ist besser als ein gesalzenes Passwort?Ich glaube nicht, dass Sie das erwähnen.


Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 4.0-Lizenz, unter der er vertrieben wird.
Loading...