15.4 Hash-Funktionen – hashlib 

Das Modul hashlib der Standardbibliothek implementiert die gängigsten sogenannten Hash-Funktionen. Ganz allgemein sind das sehr komplexe Algorithmen, die aus einem Parameter, zumeist einem String, einen sogenannten Hash-Wert berechnen. Wozu kann ein solcher Hash-Wert verwendet werden?
Nun, stellen Sie sich einmal vor, Sie würden eine Foren-Software entwickeln, die später für eine Community im Internet eingesetzt werden soll. Bevor ein Benutzer Beiträge im Forum verfassen darf, muss er sich mit seinem Benutzernamen und dem dazu passenden Passwort anmelden. Natürlich ist es im Sinne des Forenbetreibers und vor allem des Benutzers selbst, dass das Passwort nicht in falsche Hände gerät. Es stellt sich also die Frage, wie die Anmeldeprozedur möglichst sicher gestaltet werden kann.
Die intuitivste Möglichkeit wäre es, Benutzername und Passwort im Klartext an die Foren-Software zu übermitteln. Dort werden diese beiden Informationen mit den Anmeldedaten aller Benutzer verglichen, und bei einem Treffer wird der Zugang zum Forum ermöglicht.
Würde eine solche Software die Anmeldeprozedur tatsächlich so durchführen, müssten Benutzername und Passwort im Klartext in der internen Datenbank des Forums gespeichert werden. Das ist beim Benutzernamen kein größeres Problem, da es sich dabei im Allgemeinen um eine öffentliche Information handelt. Doch das Passwort im Klartext in einer solchen Datenbank zu speichern wäre grob fahrlässig. Stellen Sie sich einmal vor, ein Angreifer würde über eine Sicherheitslücke in einem anderen Teil der Software Zugriff auf die Datenbank erlangen. Er wäre sofort im Besitz aller Passwörter der angemeldeten Benutzer. Das wird besonders dann brisant, wenn man bedenkt, dass viele Leute das gleiche Passwort für mehrere Benutzerkonten verwenden.
Wünschenswert wäre es also, die Korrektheit eines Passworts mit an Sicherheit grenzender Wahrscheinlichkeit zu ermitteln, ohne Referenzpasswörter im Klartext speichern zu müssen. Und genau hier kommen Hash-Funktionen ins Spiel. Eine Hash-Funktion bekommt einen Parameter übergeben und errechnet daraus eine Art Prüfsumme, den sogenannten Hash-Wert. Wenn sich jetzt also ein neuer Benutzer bei der Foren-Software anmeldet und sein Passwort wählt, wird dieses nicht im Klartext in die Datenbank eingetragen, sondern es wird der Hash-Wert des Passworts gespeichert.
Beim Einloggen schickt der Benutzer sein Passwort an den Server. Dieser errechnet dann den Hash-Wert des übertragenen Passworts und vergleicht ihn mit den gespeicherten Hash-Werten.
Damit eine solche Anmeldeprozedur funktioniert und ein potenzieller Angreifer auch mit Zugriff auf die Datenbank keine Passwörter errechnen kann, müssen Hash-Funktionen einige Bedingungen erfüllen:
- Eine Hash-Funktion stellt eine Einwegkodierung dar. Das heißt, dass die Berechnung des Hash-Wertes nicht umkehrbar ist, man also aus einem Hash-Wert nicht auf den ursprünglichen Parameter schließen kann.
- Bei Hash-Funktionen treten grundsätzlich sogenannte Kollisionen auf, das sind zwei verschiedene Parameter, die denselben Hash-Wert ergeben. Ein wesentlicher Schritt zum Knacken einer Hash-Funktion ist es, solche Kollisionen berechnen zu können. Eine Hash-Funktion sollte also die Berechnung von Kollisionen so stark erschweren, dass sie nur unter extrem hohem Zeitaufwand zu bestimmen wären.
- Eine Hash-Funktion sollte möglichst willkürlich sein, sodass man nicht aufgrund eines ähnlichen Hash-Wertes darauf schließen kann, dass man in der Nähe des gesuchten Passworts ist. Sobald der Parameter der Hash-Funktion minimal verändert wird, sollte ein völlig verschiedener Hash-Wert berechnet werden.
- Zu guter Letzt sollte eine Hash-Funktion selbstverständlich sehr schnell zu berechnen sein. Außerdem müssen sich die entstehenden Hash-Werte untereinander sehr effizient vergleichen lassen.
Das Anwendungsfeld von Hash-Funktionen ist weit gefächert. So werden sie, abgesehen von dem obigen Passwortbeispiel, unter anderem auch zum Vergleichen großer Dateien verwendet. Anstatt diese Dateien untereinander Byte für Byte zu vergleichen, werden ihre Hash-Werte berechnet und verglichen. Mit den Hash-Werten lässt sich sagen, ob die Dateien mit Sicherheit verschieden oder mit großer Wahrscheinlichkeit identisch sind.
Beachten Sie, dass die Wahrscheinlichkeit einer Kollision bei den im Modul hashlib implementierten Verfahren sehr gering, aber theoretisch immer noch vorhanden ist.
15.4.1 Verwendung des Moduls 

Zunächst enthält das Modul hashlib eine Reihe von Klassen, die jeweils einen Hash-Algorithmus implementieren:
| Klasse | Algorithmus | Beschreibung |
|
hashlib.md5
|
MD5 |
Message-Digest Algorithm 5 Erzeugt aus einem beliebigen String einen 128-Bit-Hash-Wert. |
|
hashlib.sha1
|
SHA-1 |
Secure Hash Algorithm 1 Erzeugt aus einem beliebigen String einen 160-Bit-Hash-Wert. Beachten Sie, dass der SHA-1-Algorithmus bereits ansatzweise geknackt wurde, also nicht mehr zum Speichern von Passwörtern verwendet werden sollte. |
|
hashlib.sha224
|
SHA-224 |
Secure Hash Algorithm 224 Erzeugt aus einem beliebigen String einen 224-Bit-Hash-Wert. |
|
hashlib.sha256
|
SHA-256 |
Secure Hash Algorithm 256 Erzeugt aus einem beliebigen String einen 256-Bit-Hash-Wert. |
|
hashlib.sha384
|
SHA-384 |
Secure Hash Algorithm 384 Erzeugt aus einem beliebigen String einen 384-Bit-Hash-Wert. |
|
hashlib.sha512
|
SHA-512 |
Secure Hash Algorithm 512 Erzeugt aus einem beliebigen String einen 512-Bit-Hash-Wert. |
Die Verwendung dieser Klassen ist identisch. Deshalb wird sie hier exemplarisch an der Klasse md5 gezeigt.
Beim Instanziieren der Klasse md5 wird der String übergeben, dessen Hash-Wert berechnet werden soll.
>>> import hashlib
>>> m = hashlib.md5("Hallo Welt")Durch Aufruf der Methode digest wird der berechnete Hash-Wert als Bytefolge zurückgegeben. Beachten Sie, dass der zurückgegebene String durchaus nicht-druckbare Zeichen enthalten kann.
>>> m.digest() '\\7*2\xc9\xaet\x8aL\x04\x0e\xba\xdcQ\xa8)'
Durch Aufruf der Methode hexdigest wird der berechnete Hash-Wert als String zurückgegeben, der eine Folge von zweistelligen Hexadezimalzahlen enthält. Diese Hexadezimalzahlen repräsentieren jeweils ein Byte des Hash-Wertes. Der zurückgegebene String enthält ausschließlich druckbare Zeichen.
>>> m.hexdigest() '5c372a32c9ae748a4c040ebadc51a829'
15.4.2 Beispiel 

Das folgende kleine Beispielprogramm verwendet das Modul hashlib, um einen Passwortschutz zu realisieren. Das Passwort soll dabei nicht als Klartext im Quelltext gespeichert werden, sondern als Hash-Wert. Dadurch ist gewährleistet, dass die Passwörter nicht einsehbar sind, selbst wenn jemand in den Besitz der Hash-Werte kommen sollte. Auch anmeldepflichtige Internetportale wie beispielsweise Foren speichern die Passwörter der Benutzer als Hash-Wert.
import hashlib
pwhash = "578127b714de227824ab105689da0ed2"
m = hashlib.md5(raw_input("Ihr Passwort bitte: ")) if pwhash == m.hexdigest(): print "Zugriff erlaubt" else: print "Zugriff verweigert"
Das Programm liest ein Passwort vom Benutzer ein, errechnet den MD5-Hash-Wert dieses Passworts und vergleicht ihn mit dem gespeicherten Hash-Wert. Der vorher berechnete Hash-Wert pwhash ist in diesem Fall im Programm vorgegeben. Unter normalen Umständen stünde er mit anderen Hash-Werten in einer Datenbank oder wäre in einer Datei gespeichert. Wenn beide Werte übereinstimmen, wird symbolisch »Zugriff erlaubt« ausgegeben. Das Passwort für dieses Programm lautet »Mein Passwort«.




bestellen





