Andreas Bruns

Softwareentwicklung für Oldenburg und Bremen

Passwörter sicher in Datenbank ablegen

Bei vielen Systemen ist eine Anmeldung des Anwenders mit Benutzername und Passwort nötig. Als Anwender kann man den Anmeldemechanismus der Systeme leider nicht überprüfen und muss sich auf die Sorgfalt der Entwickler und Betreiber verlassen. Zu viel Vertrauen sollte man dabei selbst großen Anbietern von Webseiten nicht entgegenbringen, wie die Meldungen bei Heise zu LinkedIn (300 Millionen Mitglieder), MySpace und Tumblr verdeutlichen (z.B. Passwort-Leck hat desaströse Ausmaße).

In einem vorherigen Artikel habe ich die wichtigsten Regeln zusammengefasst, beispielsweise:

  • ausreichend lange Passwörter mit Groß-, Kleinbuchstaben, Sonderzeichen und Ziffern
  • Passwort niemals mehrfach verwenden

Die Regeln lassen sich einigermaßen leicht befolgen. Falls ein Webseiten-Betreiber die Sicherheit der Passwörter nicht so ernst nimmt, dann ist wenigstens für den Anwender nur diese Webseite betroffen und niemand hat Zugriff auf die Daten anderer Webseiten des Anwenders.

Als Entwickler und Betreiber stellt sich natürlich die Frage: „Wie werden Passwörter sicher in einer Datenbank abgelegt?“ Es gibt einfache Regeln und komplizierte Implementierungsdetails:

  1. Passwort niemals im Klartext speichern
  2. keine eigenen Verfahren entwickeln beim Umgang mit Passwörtern
  3. Passwort wird als Hash gespeichert
  4. Hash eines Passworts wird mit Salz (Salt) gebildet
  5. Passwort wird mit langsamen Hash-Verfahren erzeugt
  6. einfache Implementierung des Hash-Verfahrens nutzen


Da ich kein Sicherheitsexperte bin, gehe ich auf die einzelnen Punkte nur kurz ein und benenne die Stichpunkte für weitere Recherchen.

Passwort als Klartext oder eigene Passwort-Verfahren

Wer eine der beiden ersten Regeln nicht befolgt hat, geht extrem leichtfertig mit den Daten seiner Anwender um. Bitte zügig handeln!

Passwort wird als Hash gespeichert

Passwörter werden nicht verschlüsselt in der Datenbank abgelegt und bei einer Prüfung wieder entschlüsselt (Verschlüsselung). Es wird stattdessen ein Hash erzeugt und in der Datenbank gespeichert. Bei Eingabe eines Anmelde-Passwortes wird ebenfalls ein Hash erzeugt und auf Gleichheit mit dem Datenbank-Hash geprüft.

Bekannte Hash-Verfahren (und teilweise nicht mehr sicher) sind beispielsweise MD5, SHA und SHA-3. Mit dem Linux-Befehl md5 lassen sich MD5-Hashes erzeugen:

md5 -s Spargelzeit
MD5 ("Spargelzeit") = a881dc3dada5a9a225e8a3880658ea44

Hash eines Passworts wird mit Salz (Salt) gebildet

Ein Passwort aus einem Hash zu bestimmen kann durch die Methoden Brute-Force (ausprobieren) oder Wörterbuchangriff (geläufige Wörter) gelingen.

Für viele einfache Zeichenfolgen sind die Hash-Werte von Hash-Funktionen bereits als Rainbow Table vorberechnet. Die Webseite md5cracker.org nutzt entsprechende Tabellen und hat auch unseren MD5-Wert a881dc3dada5a9a225e8a3880658ea44 für „Spargelzeit“ vorrätig.

Wenn bei der Erzeugung eines Hash-Wertes eine zufällige Zeichenfolge (genannt Salt) zu einem Passwort ergänzt wird, dann wird das herausfinden des Passworts mittels Brute-Force, Wörterbuchangriff oder Rainbow Table extrem erschwert. Weiter erhöhen lässt sich die Sicherheit des Passworts, indem allen Passwörtern eine systemweite Zeichenfolge ergänzt wird (genannt Pepper). Falls jemand Zugriff auf die Datenbank mit den gehashten Passwörtern bekommt, dann ist zwar der Salt-Wert bekannt, allerdings nicht der Pepper-Wert.

md5 -s MySalt-Spargelzeit
MD5 ("MySalt-Spargelzeit") = 73ff7ba8496d84b82afbea8055a27b77

Passwort wird mit langsamen Hash-Verfahren erzeugt

Dank schnellerer Computer und Cloud-Computing steht uns immer mehr Rechenleistung zur Verfügung. Bei der Erzeugung eines Hashes ist es daher wichtig, dass das Hash-Verfahren besonders langsam einen Hash berechnet. Das Warten von wenigen Millisekunden für die Erzeugung eines Hash-Wertes bei der Anmeldung eines Anwenders ist nicht schlimm. Jedoch verzögert jede Millisekunde für eine Hash-Berechnung den Aufwand für eine Brute-Force-Berechnung von vielen Millionen Hashes beträchtlich.

Einfache Implementierung des Hash-Verfahrens nutzen

Im Java-Bereich bietet uns die Java Cryptography Architecture (JCA) eine Vielzahl von Möglichkeiten. Leider muss man dafür erst einmal ein gewisses Gesamtverständnis aufbauen und abhängig vom Betriebssystem sind manche Funktionen auch nicht verfügbar. Die Hash-Bibliothek Bcrypt erfüllt die zuvor genannten Anforderungen und ist auch super einfach zu benutzen. Der Salt wird dabei von Bcrypt selber erzeugt und an den Hash angehängt. Ein User-Model des Play-Frameworks könnte folgendermaßen mit Jbcrypt 0.3m aussehen.

import org.mindrot.jbcrypt.BCrypt;

public class User extends Model  {

	public static Find<Long, User> find = new Find<Long, User>() {};
	
	String login;
	String passwordSalted;

	public User(String login, String password) {
		this.login = login;
		this.password = BCrypt.hashpw(password, BCrypt.gensalt());
	}

	public static User authenticate(String login, String password) {
		User user = find.where().eq("login", login).findUnique();
		if (user != null) {
			if (BCrypt.checkpw(password, user.passwordSalted)) {
				return user;
			}
		}
		return null;
	}
}

Fazit

Es gibt natürlich noch gute Alternativen zu Bcrypt, wie PBKDF2 und scrypt. Die Stackexchange-Frage How to securely hash passwords? sollte man sich auf jeden Fall durchlesen, wenn man selber Passwörter in der Datenbank ablegen muss. Und dann gibt es auch noch einen Artikel, warum man Bcrypt NICHT nutzen sollte 😉 Don’t use bcrypt

Kommentare sind geschlossen.