Mahlzeit,
ich habe die Aufgabe bekommen, eine neue Administrationsoberfläche zu entwickeln.
Mit dieser soll man z.B. User anlegen können. Eine Anforderung ist hierbei, dass man (als Admin) die User-Passwörter auch im Klartext auslesen kann. Über Sinn und Unsinn braucht man nicht zu diskutieren, das ist halt eine Vorgabe und damit muss ich leben
Nun habe ich mir überlegt, wie ich das Ganze trotzdem sichern kann und hatte dabei die folgende Idee:
Ganz zu Anfang wird der Admin-User angelegt. Hierbei wird zunächst wie folgt ein Salt erzeugt, daraufhin mit dem Passwort zusammengefügt und anschließend das Ganze nochmal gehasht:
Anschließend speichere ich $salt und $hashed_pw in der Datenbank. Das Ganze soll übrigens für die User genauso laufen, nur dass hier eben noch ein Feld dazukommen soll, in dem ich das Passwort VERSCHLÜSSELT speichere.
Hierzu nehme ich den User-Salt, und packe ihn zum Admin-Passwort hinzu. Anschließend bilde ich darüber einen Hash und verschlüssele mit diesem das ursprüngliche Passwort:
$user_crypt_pass wird dann in dem Tabelleneintragdes Users gespeichert.
Wie sicher oder unicher ist diese Methode?
Ich weiß, ich schieße hier ein wenig mit Kanonen auf Spatzen, aber ich möchte einfach aus Prinzip gerne starke Hash- und Verschlüsselungsalgorithmen einsetzen.
Die Idee hinter meiner Überlegung war, dass jemand, der Zugriff auf die Datenbank bekommt keine verwertbaren Daten bekommt.
Überlegungen:
1. Für SHA256 wurden im Vergleich zu MD5 und SHA1 noch keine schwerwiegenden Schwächen gefunden.
2. Die Wahrscheinlichkeit einer Kollision ist bei 256 Bit weit niedriger
3. AES ist DER Standard für symmetrische Verschlüsselung, Bruteforce lohnt sich schon in der 128-Bit-Variante nicht.
4. Durch die Wahl von AES-256 kann ich den kompletten SHA256-Hash als Passwort nehmen.
So, die letzte Frage, was wäre, wenn nun wirklich jemand Zugriff auf die Datenbank erhält. Dann kann er ja z.B. auch den Salt des Admin-Passwortes auslesen. Wenn er dann noch weiß, wie der Salt angewendet wird, kann man ja wieder "einfach" eine Rainbow-Table erstellen. Allerdings gehe ich davon aus, dass ein Salt nur solange wirksam ist, wie jemand keinen Zugriff auf den Algorithmus hat, der ihn anwendet, oder? Ich meine, wenn Datenbank und Webserver auf getrennten Maschinen laufen und dann jemand auf beide Zugriff hat, dann liegt ja schon ganz woanders etwas im Argen, oder?
Unter der Annahme könnte ein Angreifer dann nämlich Admin-Salt und Admin-Hash kriegen, aber nicht das Admin-Passwort. Und ohne dieses könnte er die User-Passwörter nicht entschlüsseln. Und selbst bei erfolgreichen Kollisionsangriffen (solange nicht das Originalpasswort gefunden wird) wäre das Ganze auch resistent, da es spätestens hier:
knallen würde.
ich habe die Aufgabe bekommen, eine neue Administrationsoberfläche zu entwickeln.
Mit dieser soll man z.B. User anlegen können. Eine Anforderung ist hierbei, dass man (als Admin) die User-Passwörter auch im Klartext auslesen kann. Über Sinn und Unsinn braucht man nicht zu diskutieren, das ist halt eine Vorgabe und damit muss ich leben
Nun habe ich mir überlegt, wie ich das Ganze trotzdem sichern kann und hatte dabei die folgende Idee:
Ganz zu Anfang wird der Admin-User angelegt. Hierbei wird zunächst wie folgt ein Salt erzeugt, daraufhin mit dem Passwort zusammengefügt und anschließend das Ganze nochmal gehasht:
PHP:
$admin_pass='tollespasswort';
$admin_salt = hash('sha256',microtime());
$admin_salted_pw = $admin_pass.$admin_salt;
$admin_hashed_pw = hash('sha256',$admin_salted_pw);
Anschließend speichere ich $salt und $hashed_pw in der Datenbank. Das Ganze soll übrigens für die User genauso laufen, nur dass hier eben noch ein Feld dazukommen soll, in dem ich das Passwort VERSCHLÜSSELT speichere.
Hierzu nehme ich den User-Salt, und packe ihn zum Admin-Passwort hinzu. Anschließend bilde ich darüber einen Hash und verschlüssele mit diesem das ursprüngliche Passwort:
PHP:
$user_pass = 'bla';
$user_salt = hash('sha256',microtime());
$user_salted_pw = $user_pass.$user_salt;
$user_hashed_pw = hash('sha256',$user_salted_pw);
$user_salted_key = $admin_pw.$user_salt;
$user_hashed_key = hash('sha256',$user_salted_key,true);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$user_crypt_pass = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$user_hashed_key,$user_pass,MCRYPT_MODE_CBC,$iv);
$user_crypt_pass wird dann in dem Tabelleneintragdes Users gespeichert.
Wie sicher oder unicher ist diese Methode?
Ich weiß, ich schieße hier ein wenig mit Kanonen auf Spatzen, aber ich möchte einfach aus Prinzip gerne starke Hash- und Verschlüsselungsalgorithmen einsetzen.
Die Idee hinter meiner Überlegung war, dass jemand, der Zugriff auf die Datenbank bekommt keine verwertbaren Daten bekommt.
Überlegungen:
1. Für SHA256 wurden im Vergleich zu MD5 und SHA1 noch keine schwerwiegenden Schwächen gefunden.
2. Die Wahrscheinlichkeit einer Kollision ist bei 256 Bit weit niedriger
3. AES ist DER Standard für symmetrische Verschlüsselung, Bruteforce lohnt sich schon in der 128-Bit-Variante nicht.
4. Durch die Wahl von AES-256 kann ich den kompletten SHA256-Hash als Passwort nehmen.
So, die letzte Frage, was wäre, wenn nun wirklich jemand Zugriff auf die Datenbank erhält. Dann kann er ja z.B. auch den Salt des Admin-Passwortes auslesen. Wenn er dann noch weiß, wie der Salt angewendet wird, kann man ja wieder "einfach" eine Rainbow-Table erstellen. Allerdings gehe ich davon aus, dass ein Salt nur solange wirksam ist, wie jemand keinen Zugriff auf den Algorithmus hat, der ihn anwendet, oder? Ich meine, wenn Datenbank und Webserver auf getrennten Maschinen laufen und dann jemand auf beide Zugriff hat, dann liegt ja schon ganz woanders etwas im Argen, oder?
Unter der Annahme könnte ein Angreifer dann nämlich Admin-Salt und Admin-Hash kriegen, aber nicht das Admin-Passwort. Und ohne dieses könnte er die User-Passwörter nicht entschlüsseln. Und selbst bei erfolgreichen Kollisionsangriffen (solange nicht das Originalpasswort gefunden wird) wäre das Ganze auch resistent, da es spätestens hier:
PHP:
$user_salted_key = $faked_admin_pw.$user_salt;
$user_hashed_key = hash('sha256',$user_salted_key,true);
$user_plain_pass = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$user_hashed_key,$user_crypt_pass,MCRYPT_MODE_CBC,$iv);
echo $user_plain_pass; // Blödsinn vom Feinsten