it-swarm.com.de

Sollten Passwörter automatisch zurückgesetzt werden, wenn sich die zugrunde liegende Methode ändert

Ich bin derzeit Ingenieur in einem Projekt in der Entwicklungsphase. Ein 'Modul' in diesem Projekt bietet die Möglichkeit zur Benutzerauthentifizierung/-autorisierung. Es ist jedoch zu unserer Sorge gekommen, dass der Passwort-Hashing-Algorithmus möglicherweise nicht dem Cop entspricht (auch bekannt als nicht BCrypt). (Das Schreckliche ist nicht ganz sicher, was es ist und woher es kommt!).

Dies muss sich natürlich ändern und der Patch wird geplant. Wir müssen natürlich alle unsere Testbenutzer aktualisieren, da ihre Passwörter die alte Hashing-Methode verwenden, was kein großes Problem darstellt. Alle unsere Demo-Benutzer werden beim Erstellen automatisiert, sodass das Skript aktualisiert wird. Die nächste Frage ist jedoch, was ist, wenn es sich um ein Produktionssystem mit aktiven und veralteten Benutzern aller Art handelt. Was wäre Best Practice.

  1. Jeder Benutzer automatisch ein Zurücksetzen des Passworts erzwingen? Dies benachrichtigt jeden Benutzer, dass sein Passwort geändert wurde, und kann Fragen/Verwirrung und den Verdacht auf eine Sicherheitsverletzung hervorrufen. Möglicherweise werden weitere Fragen gestellt, die von den Stakeholdern der Website möglicherweise nicht unbedingt beantwortet werden können.
  2. Aktualisieren Sie die Datenbank, um zu kennzeichnen, ob es sich um die neue oder die alte Methode handelt. Sobald ein Benutzer authentifiziert wurde, aktualisieren Sie sein Kennwort in der Datenbank mithilfe von. Erfordert ein wenig Logik im Dienst und der Übergang wird für jeden vorhandenen Benutzer scheinbar unmöglich sein. Das Problem ist, wenn es einen Verstoß gab, kann es offensichtlich sein, dass hier zwei Methoden vor sich gehen, und wenn sich herausstellt, dass die weniger sichere Methode so unsicher ist, kann sie offensichtlich gebrochen werden.
  3. Setzen Sie alle Passwörter mit einer BCrypted-Version des vorhandenen Hash zurück. Kennzeichnen Sie es als den alten Stil, sodass bei erfolgreicher Authentifizierung nur ein Hash des Kennworts und kein Hash eines Hashs beibehalten wird.
94
Crazy Dino

Ihre Option 1. ist eine schlechte Idee: Zusätzlich zu den von Ihnen angegebenen Gründen für Benutzererfahrung/Öffentlichkeitsarbeit geben Sie Angreifern ein Fenster, in dem Sie die Token zum Zurücksetzen von Kennwörtern abfangen und jedes Konto auf Ihrem Server gefährden können. Es löst Ihr Problem auch nicht, wenn Sie auch nur einen Benutzer haben, der zu faul ist, um sich anzumelden/sein Passwort zu aktualisieren.

Auf den ersten Blick scheinen mir sowohl 2. als auch 3. in Ordnung zu sein. Ihre Nummer 2 ist nicht weniger sicher als das, was Sie jetzt tun, aber 2. würde bedeuten, dass Sie das derzeit schwache Login für immer unterstützen müssen (oder etwas wie "Nach X Monaten löschen wir Ihr Passwort und zwingen Sie dazu) eine Wiederherstellung ", die die gewünschte Nizza-Benutzertransparenz unterbricht, also ignorieren wir das).

Betrachten wir den Fall, dass Sie Benutzer in der Datenbank haben, die sich nie wieder anmelden werden. Sowohl mit 2. als auch mit 3. müssen Sie die aktuelle Hashing-Alge in Ihrer Codebasis für immer unterstützen, nur für den Fall, dass sie sich anmelden, aber mindestens 3. hat den Vorteil, dass sie (oder besser Sie) geschützt sind Offline-Brute-Force-Angriffe, falls Ihre Datenbank jemals gestohlen wird.

Da Sie die Spalte "Flag im alten Stil" für immer behalten müssen, tun Sie sich selbst einen Gefallen und machen Sie sie zu einem int und nicht zu einem bool, damit Sie Ihr Passwort-Hashing aktualisieren müssen, falls Sie dies jemals tun müssen alg wieder können Sie aufzeichnen, auf welchem ​​ alten Stil sie sich befinden.


UPDATE: Eine sehr ähnliche Frage wurde gestellt hier und baut auf der Diskussion aus diesem Thread auf.

89
Mike Ounsworth

Wenn Sie Option 3 ausführen können, verstehe ich nicht, warum Sie die anderen überhaupt in Betracht ziehen würden. Es ist bei weitem die beste Option. Bei dieser Option wäre es mein Bauchgefühl, zwei verschiedene Salze zu verwenden, eines für den alten Algorithmus und eines für das neue mit bcrypt. Ich stelle mir ein solches Setup vor:

  1. Richten Sie Ihr neues Passwortsystem so ein, wie Sie es heute tun würden.
  2. Erstellen Sie eine neue separate Tabelle mit Feldern für Benutzername (oder ID), Hashing-Algorithmus (Name oder ID) und Salt.
  3. Überprüfen Sie bei der Anmeldung, ob der Benutzer einen Datensatz in der separaten Tabelle hat, und wenn ja, hacken Sie das Kennwort auf die alte Weise, hashen Sie das Ergebnis auf die neue Weise und vergleichen Sie es mit dem bcrypt-Hash. Wenn es übereinstimmt, salzen/hashen Sie das Passwort auf die neue Weise neu und löschen Sie den Datensatz aus der separaten Tabelle.

Der Nachteil ist, dass Sie das Kennwort einige Millisekunden länger im Speicher behalten müssen (wen interessiert das?) Und dass Sie bei jeder Anmeldung so ziemlich für immer die zusätzliche Tabellensuche durchführen müssen, bis entweder die separate Tabelle leer ist oder alte Konten leer werden veraltet genug, dass Sie bereit sind, von ihnen zu verlangen, dass sie ihr Passwort selbst zurücksetzen.

14
TTT

Beachten Sie, dass Sie Schema 3 nur verwenden können, wenn Ihr ALTES Schema mit Salz gehasht ist, es sei denn, Sie speichern das Salz SEPARAT.

Normalerweise wird das Salz zusammen mit dem Hash gespeichert, und Sie verwenden das Salz als Eingabe für die Hash-Funktion. Wenn Sie nicht genau dasselbe Salz verwenden, erhalten Sie eine völlig andere Ausgabe.

Wenn Sie newhash (oldsalt + oldhash, newsalt) verwenden, können Sie oldhash trotz des richtigen Kennworts nicht neu erstellen (da Sie kein oldsalt haben) und den endgültigen Hash nicht generieren. Gleiches gilt für alles, was Parameter enthält (z. B. hat bcrypt einen "Kosten" -Parameter - dieser muss beim Verschlüsseln festgelegt werden und ist in die Ausgabe eingebettet, damit er beim Überprüfen des Kennworts verwendet werden kann).

AUCH : Wenn Sie, wie von anderen erwähnt, speichern, dass der Hash "alt" oder "neu" ist, sollten Sie stattdessen das "Schema" speichern - wo zB 0 ist das "alte" und 1 ist bcrypt (Hinweis, ich verwende nicht "neu" - es ist jetzt "neu", wird nicht für immer "neu" sein!). Ein üblicher Weg, dies zu tun, besteht darin, am Anfang des Hashs einen Marker zu haben (dies kann bereits der Fall sein!). bcrypt verwendet eines der folgenden Standardpräfixe: "$ 2a $", "$ 2b $", "$ 2x" oder "$ 2y $". Abhängig von den möglichen Ausgaben Ihres "alten" Algorithmus müssen Sie möglicherweise Ihr eigenes Präfix erstellen, um diese zu markieren, oder Sie können mit "alles, was nicht mit" $ "beginnt, ist der alte Algorithmus davonkommen.

Und schließlich, da Sie offensichtlich (zu Recht!) Mit der Sicherheit der alten Passwörter befasst sind, würde ich vorschlagen, alle zu zwingen, ihr Passwort zu ändern, indem Sie ihnen Anweisungen mit einem Token per E-Mail senden (KEINEN LINK SENDEN! Sie möchten nicht Ihre Benutzer klicken auf einen Link! Sagen Sie ihnen einfach, dass sie sich an der üblichen Stelle anmelden sollen. Fragen Sie dann nach dem Token UND dem Passwort. Andernfalls kann jemand, der in der Vergangenheit ein Passwort gestohlen hat, das Passwort ändern und ein gültiges "neues" Passwort erhalten.

ENDLICH: Verfallsdatum haben - wenn Passwörter bis zu diesem Datum nicht geändert werden, sollten sie ungültig werden. Dieses Datum sollte in der E-Mail stehen und nicht zu weit in der Zukunft liegen (eine Woche? Hängt davon ab, wie lange Ihre Kunden brauchen, um zu antworten). Danach müssen sie die Prozeduren zum Zurücksetzen des Passworts durchlaufen.

3
AMADANON Inc.

Ich weiß nicht, wie Ihr Passwortkodierungsschema aussieht, aber wenn es nicht so schlimm ist, ist es wahrscheinlich, dass die Struktur des Passworts im alten und im neuen Format unterschiedlich ist.

Ich habe so etwas bereits in einem alten BSD-System gesehen, als das System von einer traditionellen Passwortcodierung zu einer sichereren geändert wurde. Die neue begann mit einer Zeichenfolge, die im alten Schema nicht vorhanden sein konnte. Jedes Mal, wenn ein Benutzer mit einem alten Kennwort angemeldet war, wurde sein Klartextkennwort mit der alten Methode überprüft und stillschweigend erneut gehasht und in der Kennwortdatenbank mit gespeichert die neue Methode. Nach einem Monat war kein altes Passwort in der Datenbank vorhanden, ohne dass der Endbenutzer etwas bemerkte.

Das würde irgendwo zwischen Ihrer zweiten und dritten Methode liegen.

Ich weiß, dass in einem echten Produktionswebsystem die Dinge jetzt viel schlimmer sein können, da Benutzer Wochen oder sogar Monate warten können, bevor sie erneut eine Verbindung herstellen. Aber (abhängig von der tatsächlichen Aktivität) kann es durch die Tatsache gemildert werden, dass ein Benutzer, der seit mehreren Monaten keine Verbindung mehr hergestellt hat, sein Passwort vergessen haben kann - oder Sie können ihm sagen, dass er es getan hat ... Das bedeutet, dass ich etwas warten würde länger hier wahrscheinlich 3 oder 6 Monate und nach dieser Zeit würde ich alle alten Passwörter auf einen verbotenen Wert zurücksetzen und den Benutzer zwingen, sein Passwort bei der nächsten Verbindung zurückzusetzen ... über den Bildschirm vergessenes Passwort.

Die schönen Dinge hier sind:

  • transparent für reguläre Benutzer
  • keine Änderung des Datenbankschemas - vorausgesetzt, das Kennwortfeld kann beide Stile akzeptieren
  • gelegentliche Benutzer werden einfach so behandelt, als hätten sie ihr Passwort nach Monaten vergessen, ohne es zu verwenden

Der Nachteil ist, dass Sie gezwungen sind, beide Authentifizierungsmethoden und eine automatische Aktualisierung aller Stilkennwörter gleichzeitig zu implementieren.

2
Serge Ballesta

Sie haben die von Ihnen verwendete Sprache nicht erwähnt. PHP hat seine Probleme mit verschiedenen Funktionen, die false zurückgeben sollten, wenn es in einigen Fällen true zurückgeben sollte, oder mit anderen Funktionen, die so klingen, als würden sie den Job erledigen, aber nicht über die Logik verfügen, um tatsächlich die vollständig möglichen gültigen möglichen Eingaben zu verarbeiten.

Aber dies ist der richtige Weg, um das zu tun, wovon Sie in PHP sprechen, auch wenn Sie kein PHP verwenden. Der High-Level-Code kann Ihnen einen Ausgangspunkt für die Codierung für Ihre Zwecke geben.

http://php.net/manual/en/function.password-needs-rehash.php

$password = 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';

// The cost parameter can change over time as hardware improves
$options = array('cost' => 11);

// Verify stored hash against plain-text password
if (password_verify($password, $hash)) {
    // Check if a newer hashing algorithm is available
    // or the cost has changed
    if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {
        // If so, create a new hash, and replace the old one
        $newHash = password_hash($password, PASSWORD_DEFAULT, $options);
    }

    // Log user in
}

Was ich tun würde, wäre Ihre Nummer 2 mit dem, was mit einem Int erwähnt wurde. Beim Lesen der Dokumentation zu PASSWORD_DEFAULT kann sich dies ändern, wenn bessere Algorithmen gefunden werden und diese aus Unsicherheitsgründen entfernt werden müssen, wenn PHP aktualisiert wird.

0
Eric