Geschrieben von: Christoph Wille
Kategorie: Sicherheit
This printed page brought to you by AlphaSierraPapa
Die verschiedenen Authentifizierungsmethoden des IIS sollten zumindest grob bekannt sein: Integrated, Digest und Basic Authentication, absteigend gelistet nach ihrer sicherheitstechnischen Integration mit Windows NT. Alle haben eines gemeinsam - sie greifen für die Validierung der Benutzeraccounts auf NT Accounts durch. Heute wollen wir Basic Authentication dazu überreden, unsere von NT unabhängigen Accounts zu validieren.
Relativ simpel, sodaß sich Basic Authentication in jedem am Markt befindlichen Browser wiederfindet - ein Vorteil, da man keine Benutzer ausschließt. Generell läuft es so ab: wenn der Client auf einen geschützten Bereich zugreift, so schickt der Server einen Authentication Request an den Client, dessen Header wie folgt aussehen könnten:
HTTP/1.1 401 Unauthorized Server: Microsoft-IIS/5.0 Date: Sun, 20 May 2001 17:55:41 GMT WWW-Authenticate: BASIC Realm=AspHeute Secure Area Connection: Keep-Alive Content-Length: 16 Content-Type: text/html Set-Cookie: ASPSESSIONIDGQQQQJEC=OHPFICAALDHJBKBLJKBJCNKM; path=/ Cache-control: private
Die interessanten Parts sind der HTTP Status Code in der ersten Zeile, als auch der Header WWW-Authenticate. Der Client weiß nun, daß er den Benutzer um Benutzername und Passwort fragen muß, und zeigt eine Dialogbox an:
Diese Dialogbox dürfte nun wirklich so ziemlich jedem bekannt sein. Dort gibt man nun seinen Benutzernamen und Passwort ein, und der Browser versucht nun noch einmal, das Dokument vom Server zu requesten - dieses Mal jedoch mit Benutzernamen und Passwort im Request:
HTTP_ACCEPT:image/gif, image/x-xbitmap, ... HTTP_ACCEPT_LANGUAGE:en-us HTTP_CONNECTION:Keep-Alive HTTP_HOST:localhost HTTP_USER_AGENT:Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2901) HTTP_COOKIE:visit=4%2F19%2F2001+8%3A26%3A15+PM; ASPSESSIONIDGQQQQJEC=PHPFICAAPEOPKDBODDAOPICN HTTP_AUTHORIZATION:Basic YWRtaW46cHdk HTTP_ACCEPT_ENCODING:gzip, deflate
Die hier gezeigten Header habe ich über ALL_HTTP erhalten. Der Header für den Account ist HTTP_AUTHORIZATION - allerdings könnte man die Daten (Benutzername und Passwort, grün markiert) als unlesbar bezeichnen. Wer jetzt glaubt, daß diese Daten verschlüsselt sind, ist leider schief gewickelt. Die Daten sind nur Base64 encodet, das hat mit Verschlüsselung leider nichts zu tun. Und das Decodieren könnte man sogar als Kinderspiel bezeichnen.
Gut - wäre das jetzt Basic Authentication des IIS, würde jetzt der Account gegen die NT Accountdatenbank verglichen. Aber - wir wollen ja unsere Datenbank unterschieben, deshalb müssen einige Vorbereitungen getroffen werden.
Der wichtigste Punkt, den wir uns vor Augen führen müssen ist der, daß wir mittels ASP die Basic Authentication am IIS vorbei durchführen. Im Endeffekt führt der IIS immer nur anonyme Zugriffe durch, was im Unterschied bei "normaler" Basic Authentication nicht der Fall ist: dort werden die Zugriffe dann mit dem impersonierten Account durchgeführt.
Die Authentifizierung des Clients wird bei "normalen" IIS Zugriffsmethoden per NTFS Zugriffberechtigungen "provoziert". Da wir die NTFS Berechtigungen nicht angreifen, müssen wir die Authentifizierung anders provozieren: wir müssen die 401er Fehler selbst generieren, und auch selbst abfangen, ohne daß uns der IIS mit seinen anderen Methoden in die Quere kommt.
Eine davon ist Integrated Authentication. Diese sollte abgeschaltet werden, wie im folgenden Screenshot gezeigt:
Jetzt sind wir "in charge", und können (beinahe) schalten und walten, wie wir wollen.
Zuerst möchte ich meine Site-Sicherheitsarchitektur vorstellen, bevor ich die Basic Authentication code. Da wir unsere Sicherheit selbst verwalten, müssen auch alle Seiten separat gesichert werden, sodaß niemand darauf Zugriff bekommt, der nicht eingeloggt ist. Dazu eignen sich Includes, die dann in die jeweiligen Dateien eingebunden werden können.
Hier das Beispiel einer minimalen default.asp:
<!-- #include file="securitycheck.asp"--> <html> <head><title>Secure Area</title></head> <body> Welcome 2 the secured area! </body> </html>
Die wirklich interessante Datei ist somit securitycheck.asp:
<% If Not Session("SecArea_LoginGranted") Then Session("IntendedTarget") = Request.ServerVariables("SCRIPT_NAME") & _ "?" & Request.ServerVariables("QUERY_STRING") Response.Redirect "login.asp" Response.End End If %>
Falls der Benutzer nicht eingeloggt ist, wird er zur Datei login.asp umgeleitet. Allerdings speichere ich mir zuvor noch den aktuellen Dateinamen plus den QueryString, um den User nach erfolgreichem Login sofort zu seiner ursprünglich gewünschten Seite zurückschicken zu können. Nützlich, aber eigentlich auch nicht wirklich weltbewegend.
Bleibt also nur login.asp, wo sich denn auch tatsächlich der interessante Code findet:
<% Option Explicit Response.Buffer = True ' for iis 4.0 machines Const strThisRealm = "AspHeute Secure Area" Dim strUName, strPwd, strTargetPage GetAuthInfo strUName, strPwd If "" = strUName And "" = strPwd Then RequestAuthentication strThisRealm Response.End End If ' log in the user... here: hardcoded If "admin" = strUName And "pwd" = strPwd Then Session("SecArea_LoginGranted") = True strTargetPage = Session("IntendedTarget") ' check: no infinite loops please! If ("" = strTargetPage Or _ LCase(strTargetPage) = LCase(Request.ServerVariables("SCRIPT_NAME"))) Then strTargetPage = "default.asp" End If Response.Redirect strTargetPage Response.End Else RequestAuthentication strThisRealm Response.End End If %>
Dieser Code ruft zwei Methoden auf, die ich später vorstelle: RequestAuthentication und GetAuthInfo. Erstere schickt den 401er Statuscode um die Authentifizierung zu provozieren, und letztere decodiert den HTTP_AUTHORIZATION Header und liefert Benutzernamen und Passwort.
Der Login des Benutzers (If "adm...") ist mit Absicht hardcodiert - hier müssen Sie nur eine Funktion Ihrer Wahl aufrufen, um zB Benutzer anhand einer speziellen Datenbank zu validieren. Ich wollte es so allgemein und anpassbar wie möglich halten.
Der im If-Block folgende Code setzt die benötigte Session-Loginvariable, und schickt den Benutzer dorthin zurück, von wo aus der Login verlangt wurde. Ich berücksichtige den QueryString, als auch mögliche Loops auf login.asp.
Alles in allem ist es, ohne den Code der beiden noch vorenhaltenen Methoden, leicht verständlich wie der Prozess abläuft: beim ersten Request existieren noch kein Benutzername und Passwort, daher wird eine Authorization verlangt. Beim zweiten Aufruf existieren dann diese (hoffentlich), und der Benutzer wird mit der Benutzerdatenbank validiert. Existiert er, wird Einlaß gewährt. Ist er non-existent, wird eine weitere Autorisierung eingeleitet (Else Zweig).
Als Abschluß nun die beiden Methoden, die die eigentliche Arbeit übernehmen:
<!-- #include file="base64.asp" --> <script language="vbscript" runat="server"> Sub RequestAuthentication(ByVal strRealm) Response.Write "401 Unauthorized" Response.Status = "401 Unauthorized" Response.AddHeader "WWW-Authenticate","BASIC Realm=" & strRealm End Sub Sub GetAuthInfo(ByRef strUsername, ByRef strPassword) Dim strAuth, strUserPwdPortion, nPos strAuth = Request.ServerVariables("HTTP_AUTHORIZATION") strUsername = "" strPassword = "" ' Check for basic authentication If ("basic" = LCase(Left(strAuth, 5))) Then strUserPwdPortion = Base64decode(Mid(strAuth, 7)) nPos = InStr(strUserPwdPortion, ":") If nPos > 1 Then strUsername = Left(strUserPwdPortion, nPos - 1) strPassword = Mid(strUserPwdPortion, nPos + 1) End If End If End Sub </script>
Die Funktionalität für Base64 Codierung und Decodierung habe ich in die Includedatei base64.asp verfrachtet. Verwendet wird Base64decode in der Funktion GetAuthInfo, bevor Benutzername und Passwort aus dem String herausgeparst werden können. Der Rest sind einfache Stringoperationen.
Die Funktion RequestAuthentication ist noch einfacher gestrickt. Hier wird nur der Response Status verändert, und ein Header für die Authentifizierung gesetzt. Der Realm kann in login.asp durch die Konstante strThisRealm gesetzt werden, und scheint in der Dialogbox auf.
Damit wären wir auch schon am Ende des Codes angelangt. Bis auf das Aufparsen von Base64 ist das benötigte ASP Wissen nicht als "Rocket Science" zu qualifizieren.
Mit wenig Code und wenig Konfigurationsarbeit kann man Basic Authentication mittels ASP implementieren. Der Nachteil von Basic Authentication - keine Verschlüsselung der Accountdaten ohne SSL - bleibt aber leider dennoch bestehen.
This printed page brought to you by AlphaSierraPapa
Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20010521.zip
Erstellen eines HTTP Test Tools
http:/www.aspheute.com/artikel/20000508.htm
Formular-basierte Basic Authentication
http:/www.aspheute.com/artikel/20010608.htm
Generieren eines sicheren Paßwortes
http:/www.aspheute.com/artikel/20000531.htm
Passwörter mit SHA1 absichern
http:/www.aspheute.com/artikel/20010330.htm
Verwendung von SSL Test-Certificates
http:/www.aspheute.com/artikel/20000630.htm
Verzeichnissicherheit mit NTFS und IIS Authentifizierung
http:/www.aspheute.com/artikel/20001109.htm
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.