Bevorzugte Methode zum Speichern von Passwörtern in der Datenbank


76

Was ist Ihre bevorzugte Methode / Datentyp zum Speichern von Kennwörtern in einer Datenbank (vorzugsweise SQL Server 2005). In einigen unserer Anwendungen habe ich zunächst die .NET-Verschlüsselungsbibliotheken verwendet und sie dann als Binärdatei in der Datenbank gespeichert (16). Ist dies die bevorzugte Methode oder sollte ich einen anderen Datentyp verwenden oder mehr Speicherplatz als 16 zuweisen?


1
Ich habe das Gefühl, dass dies ein Betrug ist, aber was ich für einen Betrug hielt, stellte sich heraus, dass es sich um die tatsächlichen DB-Anmeldungen handelte und nicht nur um das Speichern von Anwendungs- / Site-Anmeldungen.
TheTXI

1
Könnten Sie bitte Ihre Frage klären, um zu erklären, ob Sie "Verschlüsselungs-" oder "Hashing" -Funktionen verwenden? Ich denke, Sie meinen letzteres, aber der Unterschied ist sehr bedeutend.
Ine

Antworten:


82

Ich speichere das gesalzene Hash-Äquivalent des Passworts in der Datenbank und niemals das Passwort selbst und vergleiche dann immer den Hash mit dem generierten, was der Benutzer übergeben hat.

Es ist zu gefährlich, die wörtlichen Passwortdaten jemals irgendwo zu speichern. Dies macht eine Wiederherstellung unmöglich, aber wenn jemand ein Passwort vergisst oder verliert, können Sie einige Überprüfungen durchführen und ein neues Passwort erstellen.


@ Quinton: Das ist ziemlich genau das, was ich tue. Mit den .net-Verschlüsselungsbibliotheken wird das Passwort gehasht und dann übergebe ich es an die Datenbank und speichere es als Binärdatei. Ich kann Passwörter nur vergleichen, indem ich Benutzereingaben hashe und sie mit dem Gespeicherten vergleiche.
TheTXI

1
Ich empfehle jbcrypt, wenn Sie mit Java arbeiten. Extrem einfach zu bedienen
Jens Schauder

13
Wir speichern auch gesalzene Passwörter. In unserem Fall konvertieren wir das 160-Bit-Muss in base64 und speichern es in einem Varchar - es macht die Sache nur einfacher (Strings sind leichter zu lesen / schreiben / anzusehen). Zusätzlich zu einem globalen Salt salzen wir mit der Benutzer-ID (sid oder guid) vor, damit zwei Benutzer mit demselben Kennwort nicht denselben Hash angeben. Dies erschwert Wörterbuchangriffe (höhere CPU-Kosten) und verhindert, dass Sie das Kennwort für mehrere gleichzeitig ermitteln, wenn alle dasselbe Kennwort auswählen.
Ian Boyd

@ IanBoyd, falls Sie die Salzmethode nicht geändert haben, machen Sie es falsch. Es sollte zufällig sein, mit genügend Entropie und benutzerspezifisch. In diesem Fall halten Sie sich nur an Letzteres.
Francisco Presencia

@FranciscoPresencia Seitdem bin ich zu bcrypt gewechselt. Die kanonische bcrypt-Implementierung generiert für jeden Hash zufälliges Salt. Die kanonische Implementierung konvertiert auch den 22-Byte-Hash in base64, der zum einfachen Speichern in einer varcharDatenbankspalte geeignet ist . Das letzte gute Denken ihres Teils ist das Definieren eines Formats ihrer Hash-Zeichenfolge, in dem das Salz in der Zeichenfolge enthalten ist.
Ian Boyd

49

DIE bevorzugte Methode: Speichern Sie niemals Passwörter in Ihrer Datenbank. Nur Hashes davon. Nach Geschmack Salz hinzufügen.


6
mod up, musste es tun, nur für den
Jakub

Ich grinste auch darüber.
Ian Boyd

15

Ich mache dasselbe, was Sie beschrieben haben, außer dass es als String gespeichert ist. I Base64 codiert den verschlüsselten Binärwert. Der zuzuweisende Speicherplatz hängt vom Verschlüsselungsalgorithmus / der Verschlüsselungsstärke ab.

Ich denke, Sie machen es richtig (vorausgesetzt, Sie verwenden ein Salz ).


9
  1. Speichern Sie den Hash des gesalzenen Passworts, z. B. bcrypt (nounce + pwd). Möglicherweise bevorzugen Sie bcrypt gegenüber SHA1 oder MD5, da es CPU-intensiv eingestellt werden kann, wodurch ein Brute-Force-Angriff viel länger wird.
  2. Fügen Sie dem Anmeldeformular nach einigen Anmeldefehlern ein Captcha hinzu (um Brute-Force-Angriffe zu vermeiden).
  3. Wenn Ihre Anwendung über den Link "Passwort vergessen" verfügt, stellen Sie sicher, dass das neue Passwort nicht per E-Mail gesendet wird. Stattdessen sollte ein Link zu einer (gesicherten) Seite gesendet werden, auf der der Benutzer ein neues Passwort definieren kann (möglicherweise erst nach Bestätigung) von einigen persönlichen Informationen, wie zum Beispiel dem Geburtsdatum des Benutzers). Wenn Ihre Anwendung es dem Benutzer ermöglicht, ein neues Kennwort zu definieren, stellen Sie sicher, dass der Benutzer das aktuelle Kennwort bestätigen muss.
  4. Sichern Sie natürlich das Anmeldeformular (normalerweise mit HTTPS) und die Server selbst

Mit diesen Maßnahmen sind die Passwörter Ihres Benutzers ziemlich gut geschützt gegen:

  1. => Offline-Wörterbuchangriffe
  2. => Live-Wörterbuch-Angriffe
  3. => Denial-of-Service-Angriffe
  4. => alle möglichen Angriffe!

All diese Maßnahmen können schnell umgesetzt werden und bieten mit minimalem Aufwand einen ziemlichen Durchschlag! +1 =)
Luke Antins

Beziehen sich DOS-Angriffe auf die Passwortsicherheit?
Arj

1
@ a12jun: Wenn Sie auf Ihrer Website einen Link "Passwort vergessen" mit einer einfachen Eingabe "Anmelden" und die Schaltfläche "Bitte generieren Sie ein neues Passwort und senden Sie es mir per E-Mail" haben, kann dies jeder, der Ihr Login kennt zwingen Sie, Ihr Passwort zu ändern. Wenn er dies so automatisiert, dass es alle 10 Sekunden ausgeführt wird, kann er Ihnen den Zugriff auf Ihr Konto verweigern. Wenn er dies gegen Tausende von Benutzern ausführt, kann er wahrscheinlich viele von ihnen dazu bringen, Ihren Dienst nicht zu mögen. Richtlinie Nr. 3 kann Sie davor schützen, das habe ich gemeint (es war nicht sehr klar, muss ich zugeben). Sicherheit = Vertraulichkeit, Integrität, Verfügbarkeit .
MiniQuark

8

Da das Ergebnis einer Hash-Funktion eine Reihe von Bytes im Bereich von 0 bis 255 (oder -128 bis 127, abhängig von der Vorzeichen Ihres 8-Bit-Datentyps) ist, ist es am sinnvollsten, sie als rohes Binärfeld zu speichern , da es die kompakteste Darstellung ist und keine zusätzlichen Codierungs- und Decodierungsschritte erfordert.

Einige Datenbanken oder Treiber bieten keine gute Unterstützung für binäre Datentypen, oder manchmal sind Entwickler mit ihnen einfach nicht vertraut genug, um sich wohl zu fühlen. In diesem Fall ist es akzeptabel, eine Binär-zu-Text-Codierung wie Base-64 oder Base-85 zu verwenden und den resultierenden Text in einem Zeichenfeld zu speichern.

Die Größe des erforderlichen Feldes wird durch die von Ihnen verwendete Hash-Funktion bestimmt. MD5 gibt immer 16 Bytes aus, SHA-1 gibt immer 20 Bytes aus. Sobald Sie eine Hash-Funktion ausgewählt haben, bleiben Sie normalerweise dabei, da zum Ändern alle vorhandenen Kennwörter zurückgesetzt werden müssen. Wenn Sie also ein Feld mit variabler Größe verwenden, erhalten Sie nichts.


In Bezug auf die "beste" Art, das Hashing durchzuführen, habe ich versucht, viele Antworten auf andere SO-Fragen zu diesem Thema zu geben:


Wenn Sie meine Frage etwas genauer lesen, werden Sie feststellen, dass ich mich in Bezug auf Datentyp und für das Feld zugewiesenen Speicherplatz mehr auf den tatsächlichen Speicher konzentriere.
TheTXI

Aber +1 für die Bereitstellung zusätzlicher Informationen für andere, die möglicherweise später kommen.
TheTXI

Direkt am. Es sieht so aus, als wäre ich nicht der einzige, dem das fehlt;)
erickson

4

Ich verwende den sha-Hash des Benutzernamens, eine Anleitung in der Webkonfiguration, und das Passwort, das als varchar (40) gespeichert ist. Wenn sie Brute Force / Wörterbuch wollen, müssen sie auch den Webserver für die Guid hacken. Der Benutzername unterbricht die Erstellung einer Regenbogentabelle in der gesamten Datenbank, wenn das Kennwort gefunden wird. Wenn ein Benutzer seinen Benutzernamen ändern möchte, setze ich gleichzeitig das Passwort zurück.

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
    username.ToLower().Trim(),
    ConfigurationManager.AppSettings("salt"),
    password
);

Ich habe den Benutzernamen als Salz hinzugefügt. Dann konnten wir einen Benutzer nicht umbenennen. Wir haben auf die Verwendung von Salt mit der ID, der Guid, der Sid oder einem anderen Ersatzschlüssel des Benutzers umgestellt.
Ian Boyd

wahr, guter Anruf. Auf diese Weise müssen Sie das Passwort nicht zurücksetzen, wenn Sie einen Benutzer umbenennen
Shawn

3

Ein einfacher Hash des Passworts oder sogar (Salt + Passwort) ist im Allgemeinen nicht ausreichend.

sehen:

http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/

und

http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords

Beide empfehlen die bcrypt-Algorithmen. Kostenlose Implementierungen finden Sie online für die beliebtesten Sprachen.


Tolle Links, die über die oberflächlichen Sicherheitsbedenken hinausgehen. Wäre es für absichtlich langsame Algorithmen wichtig, die Hashes auf der Clientseite berechnen zu lassen, um den (möglicherweise bereits ziemlich ausgelasteten) Server nicht zu überlasten?
Cheduardo

Nicht wirklich. Das Ziel ist einfach, es "etwas" langsamer zu machen. Nur um Ihnen eine Idee zu geben. Ich kann SHA1 ungefähr 200K Passwörter pro Sekunde auf Quad-Core-System hashen. Ich bezweifle, dass irgendjemand 200K gleichzeitige Anmeldungen pro Sekunde verarbeiten muss. Sie verwenden also eine Funktion wie PBKDF2 oder bcrypt, um sie zu verlangsamen und nur 100 Hashes pro Sekunde zu sagen (erhöht die Brute-Force-Zeitachse um den Faktor 200).
Gerald Davis

3

Sie können mehrere Hashes in Ihrer Datenbank verwenden, dies erfordert nur ein wenig zusätzlichen Aufwand. Es lohnt sich jedoch, wenn Sie der Meinung sind, dass die geringste Chance besteht, dass Sie in Zukunft weitere Formate unterstützen müssen. Ich werde oft Passworteinträge wie verwenden

{hashId} $ {salt} $ {Hash-Passwort}

Dabei ist "hashId" nur eine Zahl, die ich intern verwende, um zu erkennen, dass ich beispielsweise SHA1 mit einem bestimmten Hash-Muster verwende. "Salz" ist ein Base64-codiertes zufälliges Salz; und "Hash-Passwort" ist ein Base64-codierter Hash. Wenn Sie Hashes migrieren müssen, können Sie Personen mit einem alten Kennwortformat abfangen und sie bei der nächsten Anmeldung dazu bringen, ihr Kennwort zu ändern.

Wie andere bereits erwähnt haben, möchten Sie mit Ihren Hashes vorsichtig sein, da es einfach ist, etwas zu tun, das nicht wirklich sicher ist, z. B. ist H (Salz, Passwort) weitaus schwächer als H (Passwort, Salz), aber gleichzeitig möchten Sie es Stimmen Sie den Aufwand dafür mit dem Wert des Website-Inhalts ab. Ich werde oft H (H (Passwort, Salz), Passwort) verwenden.

Schließlich sind die Kosten für die Verwendung von Base64-codierten Kennwörtern im Vergleich zu den Vorteilen der Verwendung verschiedener Tools, die Textdaten erwarten, gering. Ja, sie sollten flexibler sein, aber sind Sie bereit, Ihrem Chef mitzuteilen, dass er sein bevorzugtes Tool von Drittanbietern nicht verwenden kann, weil Sie ein paar Bytes pro Datensatz speichern möchten? :-)

Bearbeitet, um einen weiteren Kommentar hinzuzufügen: Wenn ich absichtlich einen Algorithmus vorschlagen würde, der sogar eine Zehntelsekunde lang jedes Passwort hasht, hätte ich das Glück, einfach aus dem Büro meines Chefs gelacht zu werden. (Nicht so glücklich? Er würde etwas aufschreiben, um es bei meiner nächsten jährlichen Überprüfung zu besprechen.) Das Brennen dieser Zeit ist kein Problem, wenn Sie Dutzende oder sogar Hunderte von Benutzern haben. Wenn Sie 100.000 Benutzer ansprechen, melden sich normalerweise mehrere Personen gleichzeitig an. Sie brauchen etwas schnelles und starkes, nicht langsames und starkes. Das "aber was ist mit den Kreditkarteninformationen?" ist bestenfalls unaufrichtig, da gespeicherte Kreditkarteninformationen nicht in der Nähe Ihrer regulären Datenbank liegen sollten und von der Anwendung ohnehin verschlüsselt würden, nicht von einzelnen Benutzern.


Es gibt kein schnelles und starkes Hashing. Es tut uns leid. Wenn es für Sie schnell ist, ist es für einen Brute-Force-Angreifer schnell. Die Verwendung einer Schlüsselableitungsfunktion ist eine gültige Methode zur Kennwortverstärkung.
Gerald Davis

2

Wenn Sie mit ASP.Net arbeiten, können Sie die integrierte Mitgliedschafts-API verwenden.

Es unterstützt viele Arten von Speicheroptionen, einschließlich; Einweg-Hash, Zweiweg-Verschlüsselung, md5 + Salt. http://www.asp.net/learn/security für weitere Informationen.

Wenn Sie nichts Besonderes brauchen, ist dies ideal für Websites.

Wenn Sie ASP.Net nicht verwenden, finden Sie hier einen guten Link zu einigen Artikeln von 4guys und Codeproject

http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption. aspx


2

Da es bei Ihrer Frage um Speichermethode und -größe geht, werde ich darauf eingehen.

Der Speichertyp kann entweder eine Binär- oder eine Textdarstellung sein (base64 ist die häufigste). Binär ist kleiner, aber ich finde es einfacher, mit Text zu arbeiten. Wenn Sie pro Benutzer Salting durchführen (anderes Salt pro Passwort), ist es einfacher, Salt + Hash als einzelne kombinierte Zeichenfolge zu speichern.

Die Größe ist vom Hash-Algorithmus abhängig. Die Ausgabe von MD5 beträgt immer 16 Bytes, SHA1 immer 20 Bytes. SHA-256 und SHA-512 sind 32 bzw. 64 Bytes. Wenn Sie die Textcodierung verwenden, benötigen Sie je nach Codierungsmethode etwas mehr Speicherplatz. Ich benutze Base64, weil der Speicher relativ billig ist. Base64 benötigt ein um ca. 33% größeres Feld.

Wenn Sie pro Benutzer gesalzen haben, benötigen Sie auch Platz für den Hash. Alles zusammen 64-Bit-Salt + SHA1-Hash (160 Bit) Base64-codiert benötigt 40 Zeichen, also speichere ich es als char (40).

Wenn Sie es richtig machen möchten, sollten Sie keinen einzigen Hash verwenden, sondern eine Schlüsselableitungsfunktion wie RBKDF2. SHA1- und MD5-Hashes sind wahnsinnig schnell. Selbst eine Single-Threaded-Anwendung kann etwa 30.000 bis 50.000 Kennwörter pro Sekunde haschen, das sind bis zu 200.000 Kennwörter pro Sekunde auf einem Quad-Core-Computer. GPUs können 100x bis 1000x so viele Passwörter pro Sekunde hashen. Mit solchen Geschwindigkeiten wird Brute-Force-Angriff zu einer akzeptablen Angriffsmethode. Mit RBKDF2 können Sie die Anzahl der Iterationen angeben, um zu optimieren, wie "langsam" Ihr Hashing ist. Es geht nicht darum, das System in die Knie zu zwingen, sondern eine Reihe von Iterationen auszuwählen, damit Sie die Obergrenze für den Hash-Durchsatz begrenzen (z. B. 500 Hashes pro Sekunde). Eine zukunftssichere Methode wäre, die Anzahl der Iterationen in das Passwortfeld aufzunehmen (Iterationen + Salt + Hash). Dies würde es ermöglichen, in Zukunft immer mehr Iterationen durchzuführen, um mit leistungsstärkeren Prozessoren Schritt zu halten. Um noch flexibler zu sein, verwenden Sie varchar, um in Zukunft potenziell größere / alternative Hashes zu ermöglichen.

Die .Net-Implementierung lautet RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.