Kleine Vorgeschichte
Heute habe ich mir die Möglichkeit angeschaut, eigene MembershipProvider für ein ASP.NET MVC Projekt zu schreiben. Selbstverständlich wollte ich die Passwörter in der Datenbank nur als Hash speichern. Gleich ist mir wieder ein altes Problem aufgefallen, welches mir auch damals bei PHP aufgefallen ist. Vorteil der Hashmethode ist die fehlende Möglichkeit, wieder in Klartext umgewandelt zu werden. Allerdings ist der Hash immer gleich.
So wird aus

md5(„test“) immer „098f6bcd4621d373cade4e832627b4f6“

Das Problem
Selbst wenn nun ein böser Hacker die Datenbank ausliest, kommt er so an das Passwort. Der einfachste Weg liegt dabei so nahe, dass man gar nicht drauf kommt. Gebt mal so einen Hash bei Google ein, man wird das Passwort herausfinden können. Und mittlerweile gibt es ganze Rainbow-Tabellen, so dass es immer einfacher wird, die Werte zu vergleichen.
Aufgrund des Einfallsreichtums mancher Menschen tippe ich mal darauf, dass man ca. 50% der Passwörter der Otto-Normal-Benutzer daher innerhalb weniger Minuten knacken könnte.

Eine mögliche Lösung
Eine sehr elegante Möglichkeit ist es daher, den Hash zu versalzen (engl. Salt).
Die Idee dahinter ist so simpel wie erfolgreich. Ein per Zufall (im Idealfall) erzeugter String, wird vor oder hinter das Passwort gehangen, dieser String dann gehashet. An diesen Hash wird wieder der per Zufall erzeugte String angehangen (oder davor). Das Ergebnis wäre dann:

SALTHASHEDPASSWORD

Den Salt brauchen wir an der Stelle wieder, um das Passwort wieder zu vergleichen. Anhand des Klartextpasswortes und des Salt können wir wieder den Hash erstellen und so die Werte vergleichen und der Benutzer kann sich einloggen oder wird halt ausgesperrt.

Vorteil des Versalzens
Nun wo liegt der Vorteil gegenüber der salzlosen Methode? Da der Salt per Zufall erzeugt wird, kommen am Ende bei selben Eingabewerten trotzdem unterschiedliche Hashes raus. Zwar kann man diese durch den ja bekannten Salt per BruteForce das Passwort knacken, was jedoch sehr Zeitaufwendig ist. Aber der einfache Vergleich mit Rainbow-Tables ist nicht mehr möglich, da die Wahrscheinlichkeit sehr gering ist, dass es Rainbow-Tables mit genau dem Passwort und dem Salt gibt.

Meine Salzstreuerklasse
Aber zurück zum Thema, ich wollte gerne genau so eine Salt Methode nutzen.
Jedoch fand ich auf Anhieb nichts fertiges in C#. Also habe ich ein wenig gegooglet und mir was eigenes programmiert, welches ich euch nicht vorenthalten möchte.

Die Verwendung ist simpel. Die Klasse sowie eine Demokonsolenanwendung findet ihr im Anhang.
Hier eine kurze Doku zur Erklärung.

        /// <summary>
        /// Gibt die Länge des Salt zurück, sofern eine vom Benutzer gesetzt wurde. 
        /// Andernfalls wird eine Zufallslänge zurückgegeben.
        /// </summary>
        public int SaltLength


        /// <summary>
        /// Gibt einen Base64-Encoded String zurück, welcher nach dem DefaultHashAlgorithm gehashed wurde.
        /// </summary>
        /// <param name="password">Passwort</param>
        /// <param name="hashMethod">Die verwendete Hashmethode. Möglich: SHA1, SHA256, SHA384, SHA512, RIPEMD160, MD5</param>
        /// <param name="salt">Zu verendenen Salt.</param>
        /// <returns></returns>
        public string Hash(string password, string hashMethod, byte[] salt)

        /// <summary>
        /// Gibt einen Base64-Encoded String zurück, welcher nach dem DefaultHashAlgorithm gehashed wurde.
        /// </summary>
        /// <param name="password">Passwort</param>
        /// <returns></returns>
        public string Hash(string password)

        /// <summary>
        /// Gibt einen Base64-Encoded String zurück, welcher nach dem DefaultHashAlgorithm gehashed wurde.
        /// </summary>
        /// <param name="password">Passwort</param>
        /// <param name="hashMethod">Die verwendete Hashmethode. Möglich: SHA1, SHA256, SHA384, SHA512, RIPEMD160, MD5</param>
        /// <returns></returns>
        public string Hash(string password, string hashMethod)

        /// <summary>
        /// Gibt einen Base64-Encoded String zurück, welcher nach dem DefaultHashAlgorithm gehashed wurde.
        /// </summary>
        /// <param name="password">Passwort</param>
        /// <param name="salt">Zu verendenen Salt.</param>
        /// <returns></returns>
        public string Hash(string password, byte[] salt)

        /// <summary>
        /// Vergleicht ein Passwort mit einem Hash
        /// </summary>
        /// <param name="password"></param>
        /// <param name="hash"></param>
        /// <returns></returns>
        public bool VerifyHash(string password, string hash)

        /// <summary>
        /// Vergleicht ein Passwort mit einem Hash nach der angebenen Hashmethode.
        /// </summary>
        /// <param name="password"></param>
        /// <param name="hash"></param>
        /// <param name="hashMethod"></param>
        /// <returns></returns>
        public bool VerifyHash(string password, string hash, string hashMethod)

Viel Spaß damit!

Download
SaltHash.zipSaltHash.zip