Passwort-Sicherheit für Web-Anwendungen: Sicheres Hashen von Passwörtern
Klartext-Passwörter sollte es nicht mehr geben. Sind Sie Inhaber eines Web-Shops auf Basis von Standard-Komponenten, so müssen Sie sich mit diesem Thema höchstwahrscheinlich nicht beschäftigen. Die meisten Anwendungsframeworks sorgen automatisch für eine sichere Passwort-Speicherung und als Provider oder Entwickler brauchen Sie sich nicht darum zu kümmern.
Dieser Artikel wurde ebenfalls auf LinkedIn veröffentlicht.
Leider stolpere ich immer noch von Zeit zu Zeit über einen Web-Service, der mir eine Kopie meiner Registrierungsdaten als unverschlüsselte E-Mails zuschickt – darunter mein Passwort. Dies ist nicht nur unnötig sondern auch unsicher. Außerdem stellt sich die Frage, ob ein solcher Dienst seine Nutzerpasswörter im Klartext speichert. Dies geschieht meist dann, wenn Web-Anwendungen komplett maßgeschneidert sind und sich niemand um die sichere Ablage von Passwörtern und den Prozess drumherum kümmert (wie zum Beispiel das Zurücksetzen eines Passwortes, falls ein Benutzer sein Passwort vergisst).
Eine klare Warnung vorneweg: Sie sollten Passwort-Hashing nicht selbst „von Hand“ implementieren, wenn Sie nicht genau wissen, was Sie tun! Verwenden Sie ein geeignetes, anerkanntes Framework!
Warum Passwörter hashen?
Einfache Frage, einfache Antwort: Passwörter sind nach wie vor das häufigste Authentifizierungsattribut für alle möglichen Anwendungen und der durchschnittliche Benutzer neigt dazu, seine „guten“ Passwörter wiederzuverwenden. Um also die Vertraulichkeit der Passwörter Ihrer Nutzer zu schützen, sollten Passwörter nicht im Klartext gespeichert werden. Passwort-Hashes sind der einfachste Weg, dies kryptographisch sicher zu erreichen. Die meisten Software-Frameworks, die Passwort-Authentifizierung beinhalten, kümmern sich bereits automatisch darum. Andere Beispiele sind Kontokennwörter in Betriebssystemen wie Linux, Windows oder den bekannten mobilen Systemen. Sichere Passwort-Hashes sind State-of-the-Art geworden.
Ich habe gehört, Passwort-Hashes können geknackt werden. Wie ist das möglich?
Im Laufe der Jahre haben Krypto-Experten und Systementwickler von Hackern und wie diese versuchen, Hashes mittels optimierter Brute-Force-Angriffe zu knacken, gelernt. Ein Brute-Force-Angriff ist der Versuch, alle möglichen Quell- oder Eingangswerte einer bestimmten mathematischen Funktion auszuprobieren. Der Angreifer vergleicht das Ergebnis der Berechnung mit einem erwarteten Ergebnis. Dies könnte beispielsweise ein abgefangener Passwort-Hash sein. Wenn beide Werte übereinstimmen, hat der Angreifer den ursprünglichen Klartext gefunden. Wie konnte ein solcher Passwort-Hash „abgefangen“ werden? Hacker greifen Web-Anwendungen durch viele Arten von Sicherheitslücken an. Es kommt leider öfter vor, dass Angreifer Zugriff auf das Datenbank-Backend zum Beispiel eines Webshop erlangen. So erlangen sie auch Zugriff auf die Passwort-Hashes.
Eine sichere Hash-Funktion alleine ist nicht genug, um in allen Anwendungsfällen sichere Hashes zu erstellen. Wenn Sie beispielsweise Kreditkartennummern (oder IP-Adressen) ohne weitere Maßnahmen hashen, wäre der Eingangsraum für die Hash-Funktion sehr klein. Das Hashing aller möglichen Kreditkartennummern und die Speicherung der Hashwerte in einer Datenbank wäre denkbar. Ein Brute-Force-Angriff, mit dem Ziel die Eingabewerte aus den Hashwerten wiederherzustellen, wäre erfolgreich. Darüber hinaus existieren optimierte Brute-Force-Angriffe etwa unter Zuhilfenahme von „Rainbow-Tables“, welche den notwendigen Rechenaufwand drastisch reduzieren.
Passwörter sind ebenfalls relativ „kleine“ Daten. Hinzukommt dass die meisten von Durchschnittsanwendern gewählten Passwörter auf normalen Worten und nicht etwa Zufallssequenzen basieren. Dadurch können Wörterbuch-Angriffe für optimierte Brute-Force-Attacken verwendet werden. Ein Wörterbuch-Angriff bedeutet übrigens nicht, dass nur Wörter aus Wörterbüchern oder anderen Textsammlungen direkt verwendet werden, sondern auch Variationen und Permutationen auf Basis dieser Worte. Wäre zum Beispiel „Katze“ das nächste Wort in der abgearbeiteten Liste, so würde ein cleverer Brute-Force-Angriff verschiedene Permutationen gegen die Hash-Funktion probieren wie etwa „Katze1“, „Katze2“, „Katze1!“, „Katze2015“, „K4tz3“ usw. (das kann tausende von Varianten umfassen).
Sichere Passwörter
Bitte beachten Sie, dass „Katze1“ hier zwar als Beispiel verwendet wird, aber dass sich daraus nie ein sicheres Passwort konstruieren lässt. Dabei ist es unerheblich, welche Art von Hash verwendet wird. Abgesehen davon, dass das Passwort zu kurz ist, wird es in jeder Passwort-Liste vorkommen und somit einem Brute-Force-Angriff nicht standhalten. Es ist nur eine Frage der Zeit bis ein solches Passwort erfolgreich gecrackt wird.
Aus diesem Grunde wurde vor vielen Jahren der Begriff der „Passphrase“ kreiert. Benutzer sind aufgefordert, lange unvorhersagbare Passwörtern basierend auf persönlichen Sätzen zu erzeugen und mit einigen Zahlen und Sonderzeichen zu kombinieren. Sichere Kennwörter sind und bleiben die Basis für eine sichere Passwort-basierte Authentifizierung.
Solange für Angreifer kein Zugriff auf die Passwort-Hashes einer Applikation möglich ist, kann natürlich auch ein Passwort wie „Katze1“ relativ sicher sein. Dies kann zum Beispiel durch ein „Rate Limiting“ erreicht werden, etwa: Nach drei falschen Passwort-Eingaben wird der Nutzeraccount für 5 Minuten gesperrt. Dennoch bleibt ein solches Passwort bei gezielten Angriffen unsicher.
Sichere Berechnung von Hashes
Haben Sie im Zusammenhang mit Passwort-Hashing schon einmal die Begriffe „Salt“ und „Iteration Count“ gehört? Diese Begriffe stellen die Basis für den heutigen State-of-the-Art beim Passwort-Hashing dar. Der Iteration-Count oder auch „Iterationenzähler“ legt, vereinfacht formuliert, fest, wie oft eine Hash-Funktion auf ein Passwort angewendet wird. Das Passwort wird nicht einmal gehasht, sondern der Hashwert selbst wird wieder und wieder erneut gehasht. Legt man etwa einen Iteration-Count von 100000 fest, muss ein Angreifer jedes Passwort aus einer Passwortliste 100000 Mal hashen, was den Rechenaufwand des Angriffs erheblich vergrößert. Allerdings können „Rainbow-Tables“ den Rechenaufwand in bestimmten Fällen teilweise reduzieren.
Die Verwendung eines zusätzlichen und je Passwort individuellen Salts macht derartige Angriffe jedoch unbrauchbar. Ein Salt ist ein langer Zufallswert, der zur Berechnung des Hashes dem Passwort hinzugefügt wird. In der Praxis bedeutet das, dass eine Anwendung zusätzliche Werte abspeichern muss, um sichere Passwörter zu erzeugen und zu überprüfen: den Iteration-Count (global oder individuell), den Salt (individuell pro Passwort) und den Hashwert selbst. Dies gilt dann, wenn nur eine einzige Hash-Funktion zum Einsatz kommt. Werden verschiedene Hash-Funktionen verwendet, so müssen auch diese als kenntliche Parameter abgespeichert werden, da sonst keine erfolgreiche Überprüfung des vom Nutzer eingegebenen Passworts anhand des gespeicherten Hashwerts erfolgen kann.
Der verwendete Iteration-Count, die verwendete Salt-Länge und die Stärke der Zufälligkeit des Salt-Werts sind die zentralen Komponenten, die eine sichere Nutzung einer Hash-Funktion für Passwörter garantieren!
Für die Praxis stellt sich nun die Frage: Wie sind diese Komponenten in Kombination mit einer bestimmten Hash-Funktion zu implementieren? Die Antwort lautet wie zuvor: Verwenden Sie eine Standard-Implementierung! Es gibt mehrere Möglichkeiten, um alle zuvor diskutierten Komponenten sinnvoll zu implementieren. Zum Beispiel könnte man Salt und Passwort einfach zu einem langen String verketten. Kryptographisch anerkannte Implementierungen bevorzugen dazu meist jedoch eine HMAC-Funktion. Hierbei handelt es sich grob gesagt um einen Hash mit kryptographischem Schlüssel. Diese Funktion verwendet das Passwort als Schlüssel und den Salt als Eingabe für den Hash. Es gibt mehrere andere kryptographische Aspekte, die hier die Sicherheit verbessern. Man kann also deutlich sehen: Es empfiehlt sich, eine Standard-Implementierung zu verwenden und Passwort-Hashing nicht selbst per Hand umzusetzen! Ein bekannter Standard, der von einer Vielzahl an Anwendungen verwendet wird, ist PBKDF2 aus PKCS #5. Dieser wird unter anderem von TrueCrypt und seinen sicheren Nachfolgern verwendet. Die eigentliche Hash-Funktion kann dabei frei gewählt werden, bei TrueCrypt beispielsweise „SHA512“ oder „Whirlpool“.
PBKDF2 ist auch zukunftssicher. Zumindest so lange wie anerkannte Hash-Funktionen als sicher gelten. Der Iteration-Count hat kein theoretisches Maximum und kann daher verwendet werden, um den Rechenaufwand für Angreifer auf neuerer Hardware stetig anzupassen. Natürlich bedeutet die Anpassung des Iteration-Count in einer Anwendung, dass alle Nutzerpasswörter erneut gehasht werden müssen. Dies ist nicht ohne Nutzerinteraktion möglich, da die Klartext-Passwörter der Anwendung selbst ja nicht bekannt sind. Zum Beispiel könnte man aber schrittweise Benutzer dazu zwingen, ihre Kennwörter bei der nächsten Anmeldung zu ändern.
Prozesse rund um Passwort-Hashes
Wenn Sie einen Web-Shop oder ein Web-Portal betreiben und Benutzerkonten mit Passwort-Authentifizierung verwenden, müssen Sie die Tatsache, keinen Zugriff auf die Klartext-Passwörter Ihrer Nutzer zu haben, berücksichtigen. Dies stellt überhaupt kein Problem dar, wenn Sie bereits moderne Web-Standards verwenden. Falls Sie jedoch von Klartext-Passwörtern auf Passwort-Hashes wechseln, könnte dies einige Probleme verursachen. Als Beispiel sei die Passwort-Rücksetzung genannt. Wurde diese bisher als einfaches Mailing des Nutzerpassworts realisiert, ist dies nicht mehr möglich. Da E-Mails in der Regel unverschlüsselt versendet werden, war das Mailen eines Passworts ohnehin noch nie ratsam. Wieso ein Passwort im Klartext verschicken, das sicher über HTTPS gesetzt wurde? Üblich ist heutzutage jedoch, Einmallinks zu erzeugen, die die Erstellung eines neuen Zugangspassworts ermöglichen. Dieser Link wird an die Mailadresse des Benutzers gesendet. Die Passwort-Reset-Funktion erstellt einfach einen neuen Hash auf der Grundlage des neuen Passwortes. Bitte beachten Sie, dass für jedes neue Passwort auch ein neuer Salt generiert wird.
Wenn Ihre Anwendung Daten auf Basis von Benutzerpasswörtern verschlüsselt, sollten Sie bereits Key-Wrapping verwenden, um Probleme bei Passwortänderungen zu vermeiden.
Müssen Sie – aus welchen Gründen auch immer – eine Passwortänderung erzwingen, sollte verhindert werden, dass Benutzer ihr altes Kennwort erneut eingeben. Durch einfaches Hashing des neuen Passworts mit den gespeicherten Parametern des alten Hashes können Sie überprüfen, ob das alte Passwort mit dem neuen übereinstimmt.
Code-Beispiel sicheres Passwort-Hashing
Hier ist ein Beispiel für die Umsetzung von PBKDF2 für Java-basierte Web-Applikationen mit CrococryptLib:
Dieses Beispiel kann als lauffähiges Eclipse-Projekt im CrococryptLib SDK heruntergeladen und in eigenen Anwendungen frei verwendet werden.
Über
Hissen IT ist ein hochspezialisiertes Kleinunternehmen mit dem Fokus IT-Security-Softwareentwicklung und -Beratung. Inhaber Dipl.-Inform. Frank Hissen blickt auf über 19 Jahre Erfahrung in verschiedenen Positionen als Security-Experte in Entwicklungs- und Beratungsprojekten zurück. Er wurde dabei hauptsächlich für große aber auch für mittelständische Unternehmen tätig. Herr Hissen ist spezialisiert auf angewandte bzw. technische IT-Sicherheitsarbeit.
Schlagworte
Passwörter, Passwortsicherheit, Sichere Passwörter, Passwort-Verschlüsselung, Passwortschutz, Passwort Hashing, Passwort-Hacking, Passwort-Cracking, Passwort-Algorithmus
Kategorien: IT-Sicherheit Hintergrundartikel Programmieren/Java
Kommentare
Eigenen Kommentar hinzufügen
Teilen / Weiterempfehlen
Wenn Sie diese Seite gut finden, teilen Sie es doch ihren Kontakten mit: