Abhörsichere Logins für Internetportale
Heute fiel mir das Buch “Python kompakt” beim Aufräumen in die Hände. Da ich eigentlich keine Lust zum Aufrämen hatte, habe ich angefangen, darin zu blättern. Weiter hinten befindet sich zum Thema CGI-Programmierung ein Abschnitt zum Thema Login. Richtiger Weise stellt der Autor dort fest, daß es nicht gut ist, die Passwörter der Nutzer auf dem Server zu speichern. Das ist völlig korrekt und die Möglichkeit, diese Speicherung zu umgehen, die dort beschreiben wird, wird auch von den meisten Frameworks angeboten.
Sie sieht so aus, daß der Server den Benutzernamen und das Passwort miteinander verkettet und aus dieser Verkettung einen Hash-Wert (MD5, SHA1, was auch immer) bestimmt. Dieser Wert wird dann im Benutzerdatensatz abgespeichert. Beim Login wird mit den Eingaben dasselbe gemacht und der entstandene Hashwert verglichen. Schön und gut! Das Passwort kann jetzt der Datenbank nicht mehr entnommen werden und ist vor dem Administrator des Servers sicher.
Leider ist das immer noch unbefriedigend, denn nach wie vor wird das Passwort vom Browser zum Server übertragen und kann von jedem Router, Gateway, Proxy etc der an der Übertragung beteiligt ist, mitgeschrieben werden.
Ok, werden Sie sagen: Kein Problem. Wir führen die Hashwertberechnung auf der Browserseite mittels Javascript durch und übertragen nur den Hashwert an den Server. Dann gucken die bösen Hacker-Admins in die Röhre.
Dem entgegne ich: Die Gucken überhaupt nicht in die Röhre, denn denen ist es egal, ob sie das Passwort kennen oder nicht. Allein der Hashwert reicht schon, um Zugang zum Portal zu bekommen. Dazu müssen sie nur eine lokale Kopie der HTML-Seite der Loginmaske machen, diese leicht verändern, sodaß die Seite den abgehörten Hashwert an den Server schickt und fertig.
Was kann man also machen? Mein Vorschlag ist der folgende:
Wir übernehmen das Verfahren mit dem Hashwert wie oben beschrieben, sorgen aber dafür, daß trotzdem der Hashwert jedesmal anders ist. Die Lösung wie ich sie mir denke, sieht so aus:
Registrierung
- Benutzer gibt Benutzernamen B und Passwort P ein.
Browser berechnet H = h(B+P). Dabei ist h eine Hashfunktion (MD5 oder SHA) und “+” eine Verkettungsoperation. - Browser überträgt H an Server. Dieser legt H zusammen mit den anderen Benutzerdaten in der Datenbank ab.
Login
- Server erzeugt ein Los L. Das ist ein zufällige Zeichenkette. L wird zusammen mit der Loginmaske an den Browser gesendet.
- Der Browser nimmt die Benutzereingaben B und P entgegen. Er berechnet zunächst wie gehabt HB = h(B+P). Diesen Wert sendet er aber nicht zum Server sondern verquirlt ihn nun mit dem Los L:
JB = h(L+Hb) = h(L+h(B+P)). JB ist der tatsächliche Kontrollwert, der über das unsichere Internet gesendet wird. Dieser Wert ist abhängig von L und deswegen bei jedem Login ein anderer. Er nützt einem Angreifer nichts, da dieser für seinen eigenen Loginversuch von Server ein anderes Los L zugeschickt bekommen würde. - Der Server hat sich, um die Prüfung durchzuführen, das Los L für den betreffenden Client gemerkt, nimmt JB in Empfang entnimmt der Datenbank mit Hilfe des ebenfalls empfangenen Benutzernamens den gespeicherten Hashwert H. Damit berechnet er JS = h(L+H). Diesen Wert vergleicht er mit JB. Falls beide Werte identisch sind, ist der Login ok und kann zugelassen werden.
Das Verfahren erscheint mir sinnvoll und sicher, denn:
- Es steht kein Passwort in einer Datenbank
- Es wird kein Passwort übertragen
- Es wird keine andere Diskriminiante übertragen, mit der man in das System eindringen kann, denn im Wert JB ist das einmalige Los L verarbeitet, das beim einem Angriff durch einen Abhörer nicht mehr gültig ist.
Nun könnte man einwenden: Was soll der ganze Sermon, denn es gibt doch https, das dieses und eine Reihe anderer Abhör-Probleme sicher und ohne Aufwand erledigt. Wer für seine Projekte jederzeit 100€ für ein Zertifikat zur Verfügung hat: Völlig korrekt.