Passwörter mit SHA1 absichern
Geschrieben von: Christoph Wille Daß man bestimmte Teile einer Website nur für authentifizierte Benutzer zugänglich macht, ist mittlerweile bereits ein üblicher Vorgang. Das Einloggen der Benutzer findet (meist) über ein ASP Formular statt, das nicht über SSL abgesichert ist - und dabei wird das Passwort im Klartext über das Netzwerk übertragen - zur freien Entnahme sozusagen. Der heutige Artikel zeigt, wie man den potentiellen Mitlesern die Arbeit erschweren kann. Ich möchte gleich vorweg sagen, daß die heute vorgestellte Methode - das Verwenden eines Hash-Algorithmus - nach wie vor Sicherheitsprobleme in sich birgt. Das "einzige", das man gewinnt ist, daß das Passwort nicht mehr geknackt werden kann, wenn man den Netzwerktraffic mitprotokolliert. Technisch ist es aber dennoch möglich, sich als der jeweilige Benutzer auszugeben. Um auch das zu verhindern, müßte man ein zu NT ähnliches Challenge-Response System aufbauen. Dies ist zwar aufwendiger, aber durchführbar. Für heute bleiben wir aber beim Secure Hash Algorithmus SHA1 (spricht sich wie der ebensolche von Persien aus). Dieser generiert aus einem String einen 160 Bit langen Hash, der eindeutig ist - und zweitens nur in eine Richtung funktioniert: hat man den Hash, kann man daraus das Passwort nicht mehr errechnen. Wenn man also am Client das Passwort durch den Algorithmus schickt, kann jeder, der den Netzwerktraffic protokolliert, nichts mehr damit anfangen. SHA1 verwendenJetzt widmen wir uns der Frage, wie man diesen Algorithmus implementieren muß - gar nicht! Es gibt nämlich die Website JavaScript MD5, auf der man eine JavaScript Implementierung zur Gratis-Verwendung downloaden kann. Obwohl dort immer nur von Client-Side Anwendungen geredet wird, kann man diese ohne Umwege sofort am Server einsetzen (simpletest.asp): <html> <head> <title>SHA1 Simple Test</title> </head> <body bgcolor="#ffffff"> <form method="post" action="<%=Request.ServerVariables("SCRIPT_NAME")%>"> <input type="text" name="txtText2Scramble" value="SHA1 ist 160 Bit"> <input type="submit"> </form> <!-- #include file="serversidesha1.asp"--> <% str2Scramble = Trim(Request.Form("txtText2Scramble")) If "" <> str2Scramble Then Response.Write "<pre>" & calcSHA1(str2Scramble) & "</pre>" End If %> </body> </html> Ich habe mir erlaubt, eine kleine Includedatei zu erstellen, die auf die sha1.js verweist, die man von JavaScript MD5 downgeloadet hat. Es ist nur ein server-side Wrapper der einfachsten Art: <script language="JScript" runat="server" src="sha1.js"> </script> In sha1.js findet sich auch die Implementierung der Funktion calcSHA1, die ich in meinem bescheiden kurzen server-side Code aufrufe. Als Ausgabe erhalte ich einen 40 Zeichen langen String, der die hexadezimale Repräsentation des Hashes darstellt. Die Login SeiteDer Algorithmus funktioniert also, Zeit ihn bei einem Login Formular einzubauen. Um ein realitätsnahes Beispiel zu erstellen, enthält der heutige Download auch eine Demodatenbank, mit einer Tabelle Logins. Diese hat zwei Spalten: Username und Password. Der Praxisbezug? Auch in der Datenbank speichere ich nur den Hash des Passwortes - dadurch kann ein Hacker nirgends an das Passwort herankommen. Nachteil? Wenn ein Benutzer sein Passwort vergisst, kann man ihm nur ein neues zuweisen - was eigentlich auch deutlich sicherer ist (siehe Windows 2000 Benutzeraccounts). Ich habe die Seite zweigeteilt - eine Datei enthält das Formular, das angezeigt wird. Die andere enthält die Logik, um den Account zu überprüfen. Diese letztere Datei inkludiert das Formular, sodaß alles wie eine einzige Seite funktioniert - es läßt sich aber leichter verstehen, wenn man die Teile getrennt betrachtet. Das FormularUnser "Hauptproblem" ist das Formular, in dem der Benutzer den Benutzernamen und das Passwort eingibt. Ich muß nämlich bevor er das Formular abschickt, das Passwort mit SHA1 hashen. Und der einzige Weg dazu ist, client-seitiges JavaScript zu verwenden. Ja, ich kenne die Einwände, die jetzt kommen, aber: wer Zutritt zu einem gesperrten Bereich möchte, muß leiden, ergo JavaScript einschalten. Bevor ich Sie jetzt auf den Code von logonform.asp loslasse, noch ein Hinweis: der Validierungscode plus das Hashen des Passwortes passieren in der JavaScript Funktion Validate. <html> <head> <title>Login</title> <!--#include file="clientsidesha1.asp"--> <script language="JavaScript"> var errfound = false; function Validate() { errfound = false; myForm = document.frmLogon; if (!ValidLength(myForm.txtUsername.value,6)) error(myForm.txtUsername,"Bitte geben Sie einen Benutzernamen ein!"); if (!ValidLength(myForm.txtPassword.value,6)) error(myForm.txtPassword,"Bitte geben Sie Ihr Passwort ein (> 6 ..."); if (!errfound) { myForm.txtPassword.value = calcSHA1(myForm.txtPassword.value); } return !errfound; } //function to validate by length function ValidLength(item, len) { return (item.length >= len); } // display an error alert function error(elem, text) { // abort if we already found an error if (errfound) return; window.alert(text); elem.select(); elem.focus(); errfound = true; } </script> </head> <body bgcolor="#ffffff"> <table width="100%"> <tr><td align="center"> <table border=1> <tr><td bgcolor="#33ccff" valign="center" align="center" width="350"> <H1>Login</H1> <% if bValidationFailed Then %> <p><strong>Login fehlgeschlagen. Bitte erneut versuchen</strong></p> <% End If %> <p> <form method="post" action="<%=Request.ServerVariables("SCRIPT_NAME")%>" id=frmLogon name=frmLogon LANGUAGE="JAVASCRIPT" onsubmit="return Validate();"> <table> <tr> <td>Username:</td><td><input type=text name="txtUsername" size="20"></td> </tr> <tr> <td>Password:</td><td><input type=password name="txtPassword" size ="20"></td> </tr> <tr> <td colspan=2> <br><center> <input type="submit" value="Enter secured area"></center></td> </tr> </table> </form> </p> </td></tr></table> </td></tr></table> </BODY> </HTML> Der HTML Code für das Formular ist nichts besonderes, nur aus Sicherheitsgründen müßte man das ACTION Tag herausnehmen, daß niemand, der JavaScript ausgeschaltet hat, das Formular ohne Passwort-Hashing abschickt. Apropos Hash: SHA1 wird über die Datei clientsidesha1.asp eingebunden, die den gleichen Zweck wie sein server-seitiger Bruder erfüllt: <script language="JavaScript" src="sha1.js"></script> Die Validate Funktion ist eigentlich keineswegs "Rocket Science". Es werden die Felder überprüft (willkürlich, hier kann der Leser die Überprüfung nach eigenen Gesichtspunkten gestalten), und danach das Passwort gehasht, und wieder zurück in das Passwortfeld geschrieben. Per POST-Back geht es dann zurück an den Server, an unsere Überprüfungslogik. Überprüfung des AccountsWir bekommen einen Benutzernamen und ein gehashtes Passwort geliefert, und da in unserer Datenbank genau die gleichen Informationen gespeichert sind, brauchen wir nur eine einfache SELECT Abfrage. Der notwendige Code ist in der Datei logon.asp zu finden: <% @ Language=VBScript %> <% bValidationFailed = False If Request.ServerVariables("CONTENT_LENGTH") > 0 Then strUsername = Trim(Request.Form("txtUsername")) strPassword = Trim(Request.Form("txtPassword")) Set conn = Server.CreateObject("ADODB.Connection") Set rs = Server.CreateObject("ADODB.Recordset") strPath = Server.MapPath("logindb.mdb") strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath conn.Open strConnection rs.Open "select * from Logins where Username='" & strUsername & _ "' AND Password='" & strPassword & "'", conn If not rs.EOF and not rs.BOF then ' beliebige Daten aus der Tabelle auslesen... Session("AccessGranted") = True rs.Close conn.Close Response.Redirect "ok.asp" Response.End End if Response.AppendToLog " Logon failed: " & strUsername & " " & strPassword bValidationFailed = True End If %> <!--#include file="logonform.asp"--> Dieser Code ist selbsterklärend, und einfach zu erweitern: zB mehr Daten aus der Logins Tabelle auslesen, andere Session Variablen setzen, oder ein anderes Redirect-Ziel vorgeben. Ich habe sogar daran gedacht, fehlgeschlagene Logins in das Log mitzuprotokollieren. Ach ja, beinahe hätte ich es vergessen - die letzte Zeile inkludiert das Login-Formular, das ich in der vorangegangenen Sektion vorgestellt habe. Damit wäre unser sicherer Login realisiert. SchlußbemerkungDer SHA1 Algorithmus eignet sich nicht nur für dieses Szenario - was ist, wenn man bei einem Shop keine Cookies verwenden will, und eine Art SessionID im Querystring mitgibt? Hier kann der SHA1 Algorithmus ebenfalls helfen, denn minimalste Änderungen am Inputstring ergeben einen beinahe völlig anderen Hashwert. Andere Kundenwarenkörbe zu "erraten" wird damit beinahe unmöglich. Download des CodesKlicken Sie hier, um den Download zu starten. Verwandte Artikel
Aber bitte mit Rijndael Links zu anderen SitesWenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |