it-swarm-eu.dev

Wie implementiere ich eine "Remember Me" -Funktion sicher?

Angenommen, Sie haben bereits eine Website, auf der alle Standard-Anmeldemaßnahmen implementiert sind. Wie können Benutzer dann für einen bestimmten Zeitraum (z. B. 30 Tage) automatisch angemeldet werden? Dieser Zeitraum sollte strikt eingehalten werden. Das heißt, ich glaube nicht, dass eine gültige Lösung darin besteht, einem Cookie ein Ablaufdatum zu geben und zu hoffen, dass der Browser des Benutzers es rechtzeitig löscht.

Details des vorhandenen Anmeldesystems:

  • Ein Benutzer muss einen Benutzernamen und ein Passwort eingeben
  • Die Datenbank speichert Benutzernamen sowie strong_hash_function (Passwort + user_specific_random_salt)
  • Anmeldeformulare werden wie alle nachfolgenden Seiten über SSL geladen und gesendet

Es gibt viele Beispiele und viele mit offensichtlichen Sicherheitslücken. Verwenden wir PHP als Zielsprache, aber die Konzepte sollten auf jede Sprache anwendbar sein.

57
colithium

Meine Antwort ist unvollständig und weist in einigen Situationen einen nicht trivialen Fehler auf - siehe stattdessen @ Scotts Antwort .


Meine Antwort besteht aus zwei Teilen:

Erstens , vorausgesetzt, Ihr Bedrohungsmodell kümmert sich nicht um die Offenlegung clientseitiger Cookies , können Sie eine Nonce auf der Serverseite generieren und speichern Benutzername und andere Informationen (z. B. Client-IP, Computername, Zeitstempel, ähnliches) und senden Sie diese im Cookie. Das Nonce sollte zusammen mit dem Ablaufdatum in der Datenbank gespeichert und beide überprüft werden, wenn das Cookie zurückkommt.
Dies sollte nur ein "Erinnerungs" -Cookie sein, NICHT ein Sitzungscookie - d. H. Wenn Sie dieses Cookie ohne Sitzung erhalten, geben Sie ein neues, reguläres Sitzungscookie erneut aus. Beachten Sie auch, dass dies wie das Sitzungscookie nur über https und unter Verwendung der Attribute secure und httpOnly geliefert werden sollte und dass das Cookie natürlich einen ordnungsgemäßen Gültigkeitsbereich hat usw.

Zweitens sollten Sie für Benutzer, an die Sie sich erinnern, (wahrscheinlich abhängig von der Empfindlichkeit) einen erneuten Authentifizierungsprozess für bestimmte vertrauliche Vorgänge aufrufen. Das heißt, manchmal müssten sie ihr Passwort trotzdem erneut eingeben, aber selten und nur für sensible Vorgänge. Dies soll Angriffe wie CSRF und gemeinsame Desktop-Exposition verhindern.

31
AviD

Ich habe ausführlich über sichere Anmeldungen und Kontrollkästchen "Erinnere dich an mich" geschrieben geschrieben. Die akzeptierte Antwort ist nicht falsch, aber ich würde argumentieren, dass sie in einer Hinsicht etwas komplizierter ist als nötig und einen Bereich vernachlässigt, in dem etwas mehr Komplexität erforderlich ist.

generieren und speichern Sie eine Nonce auf der Serverseite, hashen Sie diese mit dem Benutzernamen und anderen Informationen (z. B. Client-IP, Computername, Zeitstempel, ähnliches) und senden Sie diese im Cookie. Das Nonce sollte zusammen mit dem Ablaufdatum in der Datenbank gespeichert und beide überprüft werden, wenn das Cookie zurückkommt.

Eine Implementierung, die dem Client keine Informationen zur Verfügung stellt, könnte also so aussehen ...

// Storage:
setcookie(
    'rememberme',
    hash_hmac('sha256', $username . $_SERVER['REMOTE_ADDR'], $storedNonce),
    time() + 8640000 // 100 days, for example
);
// Validation:
$valid = hash_equals(
    $_COOKIE['rememberme'],
    hash_hmac('sha256', $username . $_SERVER['REMOTE_ADDR'], $storedNonce)
);

Die offensichtliche Einschränkung besteht darin, dass Ihr Cookie unbrauchbar ist, wenn sich Ihre IP-Adresse (oder andere Informationen) ändert. Einige mögen dies als eine gute Sache ansehen, ich sehe es als unnötig feindlich gegenüber der Benutzerfreundlichkeit für Tor-Benutzer an.

Sie können das obige Zitat sicherlich so interpretieren, dass es etwas anderes bedeutet, wie auch das JSON-Web-Token eines armen Mannes. HTTP-Cookies sind jedoch auf 4 KB pro Domain beschränkt. Platz ist knapp.

Ein weiteres Problem: Wie viele Informationen enthält Ihre Datenbankabfrage über Ihre Anwendung? (Ja, ich spreche von Nebenkanälen.)


Die sichere "Remember Me" -Strategie der Paragon-Initiative

Lager:

  1. Generieren Sie eine zufällige 9-Byte-Zeichenfolge aus random_bytes() (PHP 7.0+ oder über random_compat ), Base64 codieren Sie sie auf 12. Dies wird für Datenbanksuchen verwendet.
  2. Generieren Sie eine weitere zufällige Zeichenfolge, vorzugsweise mindestens 18 Byte lang, und codieren Sie sie erneut mit base64 (bis 24+). Dies wird tatsächlich zur Authentifizierung verwendet.
  3. Speichern Sie $lookup Und hash('sha256, $validator) in der Datenbank. Natürlich mit einem bestimmten Benutzerkonto verknüpft.
  4. Speichern Sie $lookup . $validator Im HTTP-Cookie des Benutzers (z. B. rememberme).

Validierung (automatische Anmeldung):

  1. Teilen Sie den Cookie in $lookup Und $validator Auf.
  2. Führen Sie eine Datenbanksuche basierend auf $lookup Durch. Es ist in Ordnung, wenn es hier einen Timing-Seitenkanal gibt.
  3. Überprüfen Sie hash_equals($row['hashedValdator'], hash('sha256', $validator)).
  4. Wenn Schritt 3 TRUE zurückgibt, ordnen Sie die aktuelle Sitzung dem entsprechenden Benutzerkonto zu.

Sicherheitsanalyse:

  • Welche Seitenkanäle werden gemildert?
    Am wichtigsten: Es verringert die Auswirkungen von Timing-Informationslecks auf die bei der Datenbanksuche verwendete Zeichenfolgenvergleichsoperation.

    Wenn Sie eine naive zufällige Token-Authentifizierung implementiert haben, kann ein Angreifer viele Anforderungen senden, bis er ein gültiges Authentifizierungstoken für einen Benutzer findet. (Sie könnten wahrscheinlich nicht auswählen, welches Opfer sie sich ausgeben.)

  • Was ist, wenn ein Angreifer die Langzeitauthentifizierungsdatenbanktabelle verlieren kann?
    Wir haben einen SHA256-Hash des $validator In der Datenbank gespeichert, aber der Klartext für den Hash wird im Cookie gespeichert. Da es sich bei der Eingabe um einen hohen Entropiewert handelt, ist es unwahrscheinlich, dass bei der Brute-Force-Suche Ergebnisse erzielt werden. (Dies verringert auch die Notwendigkeit von beispielsweise bcrypt.)

Diese Strategie ist in Gatekeeper implementiert.

10

Das ist eine interessante Frage. Zunächst möchte ich sagen, dass ich nicht sicher bin, ob dies ohne eine gewisse Schwächung der Sicherheit der Anwendung möglich ist, aber dann abhängig von der Site, die den Kompromiss wert sein kann.

Ein Ansatz könnte also sein

Die Sitzungsstatusdatenbank muss die Zeit aufzeichnen, zu der ein Token festgelegt wurde, und die Dauer, an die es erinnert werden sollte, damit es das präsentierte Token vergleichen kann.

Wenn sich der Benutzer bei der Anwendung anmeldet, verfügt er über ein Kontrollkästchen, mit dem er angemeldet bleiben kann (idealerweise mit einer Reihe von Zeiträumen, die der Benutzer auswählen kann).

Wenn das Sitzungstoken festgelegt ist, wird dieser Zeitraum als Cookie-Ablauf verwendet. Bei nachfolgenden Besuchen wird das Cookie der Anwendung angezeigt, und der Server muss prüfen, ob es noch gültig ist (dh die Ablauffrist für die Erinnerungsfunktion wurde nicht erreicht). Wenn das Token noch gültig ist, wird der Benutzer als authentifiziert behandelt. Wenn nicht, wird das Token gelöscht und der Benutzer zum Anmeldebildschirm umgeleitet.

Probleme mit diesem Ansatz. Freigegebene Browser würden bedeuten, dass der nicht autorisierte Zugriff möglich ist.

Jeder, der Zugriff auf das Cookie erhalten kann (entweder durch eine Sicherheitsanfälligkeit auf der Website, ein Browserproblem oder durch auf dem Computer installierte Malware), kann unbefugten Zugriff auf die Website erhalten. Ein häufiger Vorschlag, um dies zu mildern, ist der Versuch, das Cookie an eine Quell-IP-Adresse zu binden (natürlich verschlüsselt oder auf dem Server gespeichert), die überprüft wird, wenn der Benutzer das Cookie präsentiert. Dies führt jedoch zu Problemen in großen Unternehmensumgebungen, in denen ein Benutzer möglicherweise auftritt von einer Reihe von IP-Adressen und kann auch anfällig für Spoofing sein.

5
Rory McCune

Sie müssen nicht auf den Browser angewiesen sein, um das Cookie zu löschen. Sie lassen die Site das Ablaufdatum des Cookies überprüfen.

Damit dies sicher ist, würde ich sagen, dass Sie dies wahrscheinlich sowieso tun müssen, da Sie das Ablaufdatum als Teil des Cookie-Werts festlegen und verschlüsseln möchten, anstatt sich auf das zu verlassen Klartext-Ablauf-Eigenschaft des Cookies selbst.

Und Sie möchten das Cookie entweder als sicher markieren und für die Dauer einer einzelnen Sitzung ein sekundäres Cookie verwenden oder die gesamte Sitzung (nicht nur den Anmeldevorgang) mit SSL schützen, um zu verhindern, dass das Cookie vom Kabel gestohlen wird und von einer nicht autorisierten Partei verwendet.

4
Xander

Dieser Artikel beschreibt einen Ansatz, der sich gegen Cookie-Diebstahl und das Erraten von Sitzungs-IDs schützt:

  • Ein "Remember Me" -Cookie besteht aus der Benutzer-ID, einem Token (große Zufallszahl) und einem Sequenz-Token (eine weitere große Zufallszahl).
  • Wenn ein Benutzer das Cookie präsentiert, wird die Datenbank nach diesen drei Informationen durchsucht.
    • Wenn gefunden, wird das Sequenz-Token neu generiert, in der Datenbank gespeichert und an den Benutzer gesendet
    • Wenn nur der Benutzername und das Token gefunden werden, wird davon ausgegangen, dass jemand anderes das Cookie gestohlen hat, weil das Sequenz-Token bereits verwendet wurde. Das System kann dann den Benutzer warnen und/oder alle gespeicherten Token von diesem Benutzer aus der Datenbank löschen.

Als zusätzliche Sicherheitsmaßnahme wird empfohlen, dass kritische Aktionen wie das Ändern der Anmeldedaten oder das Bezahlen von Dingen das Kennwort anfordern, wenn der Benutzer nur mit dem Cookie "Remember Me" authentifiziert wurde.

Die Datenbanktabelle, die die Benutzer-ID und die Token enthält, enthält auch das Ablaufdatum der Token. Es kann auch den Benutzeragenten und die IP-Adresse enthalten, sodass ein Angreifer diese ebenfalls replizieren muss. Alle Token sollten nur als Hashes gespeichert werden, da sie im Grunde genommen wie Passwörter funktionieren und es einem Angreifer, der eine Datenbank erhalten hat, ermöglichen würden, sich anzumelden.

Ich habe ein Beispielimplementierung für PHP erstellt.

0
chiborg