PHP Ich verstehe den Random Salt nicht

furryhamster

Lt. Commander
Registriert
Okt. 2008
Beiträge
1.101
Hi,

ich überarbeite zur Zeit einen Login. Das Passwort soll als Hash in der Datenbank stehen. Dabei soll ich einen random salt anwenden. allerdings verstehe ich nicht so ganz den Unterschied zu einem festen salt (außer dass die Hashwerte bei gleichen Passwörtern anders sind)

Folgendes Beispiel habe ich im Internet gefunden:
function generateSaltedHash( $data, $salt=null )
{
if( is_null($salt) ) {
$salt = substr(md5(uniqid(rand())), 0, 8);
}
return $salt.md5($salt.$data);
}

function checkSaltedHash( $data, $hash )
{
return $hash === generateSaltedHash($data, substr($hash, 0, 8));
}

Angenommen Passwort = Hans und das random generierte Salt = esel..
Also erstes mache ich aus esel ein md5 hash und nehme davon die ersten 8 ziffern, also "f8319e90". Diesen beschnittenen Hash speicher ich in der Datenbank. dann nehme ich f8319e90Hans und wieder md5 (=266acf38db238456686c471749b55e34). dort setz ich dann wieder den beschnittenen Salthash vor (=f8319e90266acf38db238456686c471749b55e34) und speicher dies als Passwort in der Datenbank.

wenn jetzt jedoch jmd kommt und es schafft auf die datenbank zugreift, sieht er ja hash und pwhash. dann brauch er ja eigl nur den Salt am anfang vom pw hash entfernen und eine brute force attacke starten mit f8319e90Beispielpasswort und den wert + f8319e90 vorgehängt mit dem pwhash vergleichen. Dies würde doch genau so lange zu bruten dauern wie komplett ohne salt oder?
irgendwas stimmt da doch an meiner logik nicht
 
Das anhängen eines Salts ist sinnvoll, da Rainbow Tables nicht mehr verwendet werden können. (Sie müssten unter Berücksichtigung des Salts neu berechnet werden :D)

Außerdem lässt sich, wie du korrekt erkannt hast, bei zwei gleichen eingaben nicht erkennen, dass sie gleich sind, was ebenfalls zur Sicherheit beiträgt.
 
gegenfrage: woher sollte denn ein 'einbrecher' wissen wo dein $salt endet und das passwort beginnt?

du koenntest natuerlich $salt_end zusaetzlich benutzen, was es noch schwieriger fuer einen potentiellen angreifer machen wuerde. oder gar ein pw komplett zerschnippeln und in falscher reihenfolge zwischen diverse $salt's verstecken.
 
ok das mit den rainbow tabellen leuchtet mit ein. nur kann ich ja auch einen festen salt nehmen als beispiel um das zu verhinden. daher versteh ich noch nicht warum ein random salt besser sein soll.
wer an den passworthast kommt, kommt doch auch automatisch an den random salt oder?

wär es nicht sicherer ich mache vom pw ein md5 und daraus ein sh1/2? zu kollisionen kanns dann ja eigl auch nicht kommen, da sh1/2 ja länger ist als md5 oder irre ich mich?

edit: @imRa: da der salt ja vor dem md5 vom pw steht, seh ich ja, was davon der salt ist, da ich das direkt vergleichen kann oder nicht? wer sich zugriff auf die datenbank verschaffen kann, kommt derjenige dann nicht auch an den php code und sieht wierum usw gehasht und angehängt ist?
 
Zuletzt bearbeitet:
imRa schrieb:
gegenfrage: woher sollte denn ein 'einbrecher' wissen wo dein $salt endet und das passwort beginnt?

Vermutlich weiß er, dass ein MD5 Hash 16 Byte lang ist (also 32 Hex-Zeichen), also ist Length($hash) - 32 == Length($salt) ;)

imRa schrieb:
[...]gar ein pw komplett zerschnippeln und in falscher reihenfolge zwischen diverse $salt's verstecken.

security by obscurity hilft in dem fall nur gegen SQL-Injections, bei denen der Angreifer keinen Zugang zum Quellcode der betreffenden Seite hat, ansonsten ist das relativ sinnlos. :freaky:
 
nein und nein xD

der trick liegt ja dabei das passwort in der zeichenfolge zu verstecken. daher waere es auch sinnvoll das passwort zu zerschnippeln und es richtig zu verstecken. damit machst du es dem angreifer alles andere als ein freude ;}

sql/php/ssh etc sollte immer strikt voneinander getrennt sein, sprich selbst wenn ein angreifer ein sql-konto erschleichen koennte so sollten diese daten keinesfalls fuer andere dienste gueltig sein.

@the-master: kling auesserst logisch xD
wenn du davon ausgehst das jemand an den quelltext kommen sollte ist eh jede sicherheitsmassnahme...mhhh...nicht mehr so sicher wie angedacht - dadurch wuerde er auch an gueltige sql-daten kommen. spaetestens ab da kann man nur noch beten das man zumindest die sql-recht richtig verteil hat.
er ging allerdings davon aus was passieren koenne wenn jemand auf die db zugreifen kann und in diesem fall wuesste er eben nicht wo das pw beginnt und wo endet - zumindest bei der schoenen schnippeltechnik ;)
 
Zuletzt bearbeitet:
furryhamster schrieb:
ok das mit den rainbow tabellen leuchtet mit ein. nur kann ich ja auch einen festen salt nehmen als beispiel um das zu verhinden. daher versteh ich noch nicht warum ein random salt besser sein soll.
wer an den passworthast kommt, kommt doch auch automatisch an den random salt oder?

wär es nicht sicherer ich mache vom pw ein md5 und daraus ein sh1/2? zu kollisionen kanns dann ja eigl auch nicht kommen, da sh1/2 ja länger ist als md5 oder irre ich mich?

Zu Kollisionen kann es immer kommen, da ja eine beliebige Eingabemenge auf 2^128 mögliche Ausgaben bei MD5 und 2^x bei anderen Hashs reduziert wird. Die sind nur so unwahrscheinlich dass es in der Praxis keine Rolle spielt.

Wenn du es jemanden wirklich schwer machen willst könntest du es in dieser weise probieren: (Das hilft natürlich auch nicht gegen Brute-Force, aber bei 4096 runden dauert dass dann noch eine ecke länger :D )

Code:
Digest = SHA512(password);
DigestTemp = SHA512(Salt);

for(i=0; i < 1 << 12; ++i){
  DigestTemp = SHA512(Digest ^ DigestTemp);
  Digest = SHA512(Digest ^ DigestTemp);
}

(Digest und Salt müssen dann in der DB gespeichert werden, wenn du Salt für jedes Passwort neu wählst, ansonsten nur Digest)
 
Der Salt soll im Grund genommen mehr Sicherheit vor Bruteforce / Rainbow tables bieten.

Angenommen ein Angreifer hat Erfolg bei seinem Angriff auf ein Benutzerkonto und du verwendest einen festen Salt. Dann kennt er zugleich den Salt für alle Passwörter der Benutzerkonten. Das passiert nicht, wenn jedes Passwort einen random, am Besten unique, Salt erhält. PHP bietet die Funktion eine unique id zu erzeugen.
 
Zuletzt bearbeitet:
irgendwie wills mir nicht einleuchten :D

meine jetzige annahme ist: der bösewicht hat zugriff auf die datenbank.
da der salt (wie im beispiel die ersten 8 ziffern vom hash eines unique random) eh beim benutzeraccount bei steht, macht es doch keinen unterschied ob der jetzt überall gleich ist oder überall unterschiedlich?
oder wird dieser wert gar nicht in der datenbank gespeichert sondern ein anderer?
irgendwie geht bei mir noch nicht hervor, wie der hacker den durch den salt nachteile hat (außer er kann keine rainbow tabelle anwenden), da er ja weiß wo der salt steht (sofern man ihn nicht komplett zerhäxelt wie bereits vorgeschlagen)
 
Okay, nochmal anders erklärt. Angenommen der Angreifer weiß, wie der Passwort-Hash zusammengesetzt ist, bspw. "$salt.$password".

Szenario nicht-random Salt: Um das Passwort herauszufinden, arbeitet der Angreifer mit Rainbow-Tabellen. Nachdem das Muster des Passwort-Hash bekannt ist, kann er theoretisch mit EINER Rainbow-Tabelle ALLE Passwörter in der Datenbank "entschlüsseln".

Szenario random Salt: Der Angreifer hat nun das Problem, dass er für jeden Passwort-Hash eine neue Rainbow-Tabelle erstellen muss, weil der dazugehörige Salt bei jedem Passwort verschieden ist.

Außerdem: Erstellst du einen Passwort-Hash aus einem festem Salt + dem Passwort, geht auch der eigentliche Sinn des Salt verloren. Denn damit werden Passwörter nicht eindeutig in der Datenbank gespeichert.

Beispiel: Benutzer A hat als Passwort "hallo". Der feste Salt sei "XYZ". Zusammen wird daraus der Hash ("halloXYZ"). Benutzer B hat ebenfalls als Passwort "hallo". Der Salt, wie gehabt "XYZ". Was passiert? Es wird ebenfalls der Hash ("halloXYZ") in den Datenbank gespeichert. Das Problem hast du nicht wenn du einen random Salt verwendest. Dann hat das Passwort von Benutzer A den Hash ("halloABC") und das Passwort von Benutzer B den Hash ("halloCDE"). Clever, oder? Beide Benutzer verwenden an sich das gleiche Passwort, was anhand der in der Datenbank gespeicherten Passwort-Hash nicht gesehen werden kann.

Einleuchtend?

Edit: Als Salt könntest du bspw. folgendes verwenden
PHP:
$salt = uniqid(mt_rand(), true);

Bitte aber niemals einen Salt aus irgendwelche Daten, die sich der Angreifer erschließen könnte, generieren. Bspw. einen Salt zusammengesetzt aus E-Mail + Benutzername oder ähnliches.
 
Zuletzt bearbeitet:
danke für die ausführliche erklärung :) denke was du da ansprichst hab ich verstanden ;)

was ich jetzt daraus schließe: der random salt erschwert es dem hacker mittels rainbow tabellen alle passwörter rauszufinden. er müsste also bei allen von vorne anfangen und das ebenso bei brute force attacken, da er ja immer wieder den random salt davor setzen müsste.
der eigentliche schwierigkeitsgrad ein einzelnes passwort zu knacken steigt dadruch nicht (sofern man wie angenommen zugriff auf die datenbank hat und die zusammensetzung des hashs erkennt) richtig?
 
Richtig... das Anfertigen von Tabellen für jede Salt-Möglichkeit oder der Brute-Force-Angriff auf jedes Passwort führen zu einem kaum zu vertretenden Aufwand...

Btw: Stand doch alles schon in der ersten Antwort:
"Das anhängen eines Salts ist sinnvoll, da Rainbow Tables nicht mehr verwendet werden können. (Sie müssten unter Berücksichtigung des Salts neu berechnet werden )"
 
Meinem Verständnis nach nicht, richtig. Aber: Der Aufwand für den Angreifer solch eine Tabelle zu erstellen ist erheblich größer. Bei den Tabellen bewegen wir uns locker in Dimensionen von 32GB+ und Berechnungszeiten von mehreren Tagen oder Wochen. Diesen Aufwand für ein einzelnes Passwort zu betreiben ist mehr als unwirtschaftlich.

Zudem kann dem Angreifer das Leben durch Verwendung neuerer Hash-Methoden (SHA-512 / Whirlpool) erschwert werden. Die Berechnung der Rainbow-Tabellen dauert länger und Bruteforce-Attacken würden wesentlich mehr Zeit benötigen, den Hash zu entschlüsseln. Unter Berücksichtigung aktueller Leistungsdaten von CPU/GPU und der Komplexität des Passwortes kann diese unter Umständen Jahre dauern.
 
Trainmaster schrieb:
Hash entschlüsseln
Ah, das böse Wort. =)

Was mir noch aufgefallen ist:
Wenn ich den Code nicht gesehen hätte, würde ich auf den Hash spontan eine SHA1 Rainbow-Table ansetzen, da er 40 Zeichen lang ist.
Damit ist wieder etwas für die "security by obscurity" getan. :D
 
so jetzt dachte ich eigl ich hätts verstanden. dem scheint nicht so...

folgendes hatte ich mir jetzt überlegt:

Den Salt erzeuge ich wie bereits erwähnt (substr(md5(uniqid(rand())), 0, 8) ). Diesen setze ich vor das Passwort und hashe das ganze mit Sha512. Das wiederum kürze ich wieder auf 32
Zeichen und hänge den Salt davor.

Bei der Methode würde ich die Salt Methode wie im Internet beschrieben anwenden. Zusätzlich wüsste man ohne PHP Code nicht um Welche verschlüsselung es sich handelt (kürzung auf 32 zeichen = md5 +8 Zeichen hash = sh1).

Habe dies einem vorgesetzten mal vorgeschlagen. wo dieser sagte dass dies auch nicht richtig wäre. Leider hat er noch keine Zeit für erklärungen.
was stimmt an der Methode denn jetzt noch nicht?
 
Naja es ist kein SHA1, sondern ein "MD5 + 8 Zeichen Salt", der so aussieht wie ein SHA1. Vielleicht hast du es falsch rüber gebracht. :)
 
der salt ist md5 ok, aber das eigentliche passwort ist doch sha2 (512), ist doch eigl das sicherste was es gibt was ich gelesen habe.
ich kann mir nicht vorstellen, dass es sicherer wäre wenn ich den salt mit sha1 / sha2 hashe, da der salt.passwort hast doch eigentlich wichtig ist oder?
und es würde ja im meinem beispiel die ersten 8 zeichen des md5 hashs in der datenbank gespeichert werden oder? da spielt doch theoretisch gar keine rolle wie der gehasht wurde :/
 
Nun, das Abschneiden des Hash (Hash Truncation) würde ich bei dieser Vorgehensweise als nicht weiter schlimm erachten. Zwar kann der Angreifer auf den verkürzten Hash einen Bruteforce-Angriff starten und theoretisch Erfolg haben. Aber der Erfolg bringt ihm nichts, weil das Ergebnis trotzdem nicht das eigentliche Passwort ist.

Dennoch spricht doch nichts dagegen, den SHA-512 in seiner eigentlichen Länge (128 Zeichen) in der Datenbank zu speichern. Dann wünsche ich dem Angreifer viel Spaß :)

Auf die Begründung deines Vorgesetzten bin ich gespannt.
 
furryhamster schrieb:
der salt ist md5 ok, aber das eigentliche passwort ist doch sha2 (512), ist doch eigl das sicherste was es gibt was ich gelesen habe.
ich kann mir nicht vorstellen, dass es sicherer wäre wenn ich den salt mit sha1 / sha2 hashe, da der salt.passwort hast doch eigentlich wichtig ist oder?
und es würde ja im meinem beispiel die ersten 8 zeichen des md5 hashs in der datenbank gespeichert werden oder? da spielt doch theoretisch gar keine rolle wie der gehasht wurde :/

Da hast du recht :)

Da du den Salt eh in der Datenbank speicherst, ist es egal wie du ihn bestimmst. Ein einfaches ermitteln von 8 (bzw. 4, wenn du 8 hex-Zeichen haben möchtest) zufälligen Bytes mit Random(0xFF) reicht da meiner Meinung nach auch aus.

Trainmaster schrieb:
Nun, das Abschneiden des Hash (Hash Truncation) würde ich bei dieser Vorgehensweise als nicht weiter schlimm erachten. Zwar kann der Angreifer auf den verkürzten Hash einen Bruteforce-Angriff starten und theoretisch Erfolg haben. Aber der Erfolg bringt ihm nichts, weil das Ergebnis trotzdem nicht das eigentliche Passwort ist.

Mit dem verkürzen des Hashs steigt die Wahrscheinlichkeit einer Kollision, sollte aber in diesem Fall nicht weiter schlimm sein.

Wieso sollte das erfolgreiche finden einer Kollision nicht das gewünschte Ergebnis liefern?

Wenn der Angreifer den zu "knackenden" Hash sowie den Salt hat (und die Methode kennt, wovon ich einfach mal ausgehe) kann er doch "problemlos" alle Möglichkeiten durchprobieren, bis er eine Kollision gefunden hat. (Je kürzer der zu vergleichende Teil des Hashs, desto wahrscheinlicher ist eine Kollision --> bei einem auf 256 bit verkürzten SHA512 Digest liegt die Wahrscheinlichkeit eine Kollision zu finden (meines Wissens nach) nicht höher, als bei SHA256)

Bitte Korrigiert mich, falls ich mich geirrt haben sollte. :)
 
Ich sehe das so. Der zu "knackende" Hash ist ein abgeschnittener SHA-2 Hash und sieht so aus, als sei es ein MD5 (32 Zeichen) oder SHA-1 (40 Zeichen) Hash. Der Angreifer kann mit seinem Bruteforce-Angriff durchaus ein Ergebnis erzielen. Bspw. liefert der vermeindliche MD5/SHA-1 Hash eine Übereinstimmung mit dem String "123456". Doch heißt das zugleich, dass das tatsächliche Reintext-Passwort dem entspricht? Mitnichten ist das Reintext-Passwort ein anderer String, bspw. "abcdef".

Der Angreifer denkt also das Ergebnis gefunden zu haben. Dennoch wird es sich mit dem vermeindlich gefundenen Passwort niemals einloggen können.

Nachtrag: Ist dem Angreifer bekannt, dass der Passwort-Hash ein abgeschnittener SHA-2 Hash ist, kann dies weitreichende Folgen haben. Jedenfalls nach meiner Überlegung. Die zusätzliche Sicherheit durch SHA-2 (128 vs 32/40 Zeichen) wäre damit enthebelt. Es besteht eine Wahrscheinlichkeit, mit einem vom Reintext-Passwort abweichenden String einen SHA-2 Hash zu erhalten, dessen erste 32 Zeichen dem abgeschnittenen SHA-2 Hash des Reintext-Passwortes entspricht. Somit würde ich dazu raten, wenn schon SHA-2 verwendet wird, den Hash auch in seiner Länge zu speichern.
 
Zuletzt bearbeitet:
Zurück
Oben