Moin!
Doch ich habs schon verstanden bis auf eins. WIE <- kann ich das ganze etwas sicherer machen?
Ich habe da so meine Zweifel, dass du die Session-Mechanismen verstanden hast.
Aber ich fang' gern nochmal bei Adam und Eva an. :)
Session hat erstmal nichts mit Login und Sicherheit zu tun, sondern bezieht sich nur darauf, dass der Browser bei jedem Request, den er macht, dem Server eine eindeutige Identifikationsmarke mitschickt, an der der Server den Browser wiedererkennt.
Als praktikabel hat sich dabei erwiesen, eine möglichst zufällig generierte ID in einem Cookie zu speichern. Alternativ wird diese ID irgendwo in der URL (bei PHP als Parameter, denkbar wäre aber auch irgendwo im Pfad), bzw. in den Formulardaten (bei POST) platziert.
Die ID muß zufällig sein, damit man sie nicht vorhersagen kann - das könnte dann nämlich auch ein böser Angreiferbrowser tun, der vom Server dann für den echten Browser gehalten wird.
Außerdem muß die ID einen sehr großen Wertebereich haben, damit man nicht durch stupides Ausprobieren aller möglichen ID-Varianten auf gültige Sessions stößt.
Bei PHP wird zur Generierung der Session-ID ein langer String gebildet, in dem die IP des Angreifers, die aktuellen Sekunden, die aktuellen Mikrosekunden sowie ein Zufallswert stehen. Dieser String wird durch die Funktion md5() geleitet und ergibt damit eine sehr sichere Session-ID, die nicht vorhersagbar ist, und die aufgrund ihres Wertebereichs auch nicht in vernünftiger Zeit annähernd effektiv durchprobiert werden kann. Ab Version 5.0.0 bietet PHP alternativ die Möglichkeit, den Zufallsstring mit sha1() zu bearbeiten, um einen noch größeren ID-Wertebereich zu erhalten.
Auf der Serverseite sorgt der Sessionmechanismus dafür, dass gewisse Werte, die die Anwendung beim ersten Request abgelegt hat, durch Übermittlung der identischen Session-ID auch beim zweiten Request wieder geladen werden und dem Skript zur Verfügung stehen.
Von außen kann man auf diese Sessionvariablen, die bei PHP im Array $_SESSION abgelegt werden, keinen Zugriff nehmen. Man kann darin nichts verändern - es sei denn, es ist ein Skript geschrieben, welches diese Variablen verändert, und welches man von außen mißbrauchen kann. Gegen Blödheit des Programmierers kann auch ein sauberer Sessionmechanismus nichts ausrichten.
Ihr habt sicher alle schonmal ein Session-System entworfen. Wie habt ihr das gemacht? Wo habt ihr Sicherheitslücken geschlossen? Und so weiter..
Ich betrachte den Standardmechanismus der Sessions, den PHP bietet, für vollkommen ausreichend selbst für sicherheitstechnisch anspruchvollere Anwendungen. Ich würde damit vielleicht kein Homebanking programmieren (was aber eher an PHP insgesamt liegt), aber jegliche Art von Shopsystemen, Logins sowie alle Anwendungen, die kein SSL benötigen.
Dementsprechend gibt es beim Standardmechanismus auch keine Lücken zu schließen. Hinzuzufügen ist allenfalls ein Mechanismus, der Logins nach einer definierten Zeitdauer ungültig macht, damit das vergessene Logout nicht doch durch Unbefugte, die Zugriff auf den eingeloggten Browser haben, mißbraucht werden kann.
Hinsichtlich der Prüfung der Logindaten gibt es zwei Modelle:
1. Es wird nur einmalig beim Login geprüft, ob die Zugangsdaten in Ordnung sind. Das Ergebnis der Prüfung wird in den Sessionvariablen abgelegt (typisch: $_SESSION['eingeloggt'] = true;). Im weiteren Verlauf wird nur geprüft, ob diese Variable existiert und true ist. Falls ja, kommt die angeforderte Seite, andernfalls das Loginformular.
2. Alternativ wird bei jedem Request (und damit auch schon beim ersten) geprüft, ob die Zugangsdaten korrekt sind. Dazu werden diese in den Sessionvariablen abgelegt und jedesmal mit der Datenbank verglichen. Falls sie korrekt sind, kommt die angeforderte Seite, andernfalls das Loginformular.
Methode 1 hat den Vorteil, dass sie mit wenig Datenbankkommunikation auskommt und üblicherweise für einfache Logins mit nur einer Berechtigungsstufe (man kriegt Zugang - oder eben nicht) verwendet wird.
Methode 2 hat den Vorteil (und Methode 1 damit den Nachteil!), dass jeder Request immer mit den aktuell gültigen Zugangsdaten geprüft wird. Somit kann man einem User den Zugang in der Datenbank entziehen, und er wird beim nächsten Request seiner laufenden Session sofort keinen Zugang mehr zu den Daten erlangen. Bei Methode 1 bleibt er solange eingeloggt und kann zugreifen, bis die Session verfällt oder er sich ausloggt.
Deshalb ist Methode 2 mit mehr Datenbankkommunikation verbunden, und eignet sich, da man die Datenbank ohnehin befragt, tendentiell eher dazu, ein Berechtigungssystem mit mehreren Stufen oder Bereichen zu verwalten. Aber selbstverständlich könnte man auch bei Methode 1 die aus der Datenbank ermittelte komplexere Zugangsberechtigung in die Sessionvariablen schreiben.
Und noch eine Bemerkung zum Begriff "Sicherheit": Sicherheit ist ein Prozess, kein Zustand. Man kann nicht hingehen und "ein Skript sicher machen", und dann hinterher sagen "das Skript ist sicher". Einfach weil Sicherheit eine vielschichtige Angelegenheit ist. Auf die Aufforderung "Wie kriege ich das sicher!" muß daher immer die Gegenfrage kommen: "Sicher wogegen?" - die Art des Angriffsszenarios ist entscheidend für die Beantwortung.
Außerdem ist Sicherheit auch immer eine Abwägungsfrage. Man kann hochsichere Systeme erstellen - die erfordern dann aber auch extreme Einschränkungen der freien Nutzbarkeit. Das klassische Beispiel ist der einzeln stehende, nicht vernetzte Computer mit den extrem geheimen Daten, der in einem Hochsicherheitsbunker untergebracht ist, und an den man nur mit Fingerabdruck und Irisscan drankommt - siehe den Film "Mission Impossible". An die Daten des Computers kommen Unberechtigte mit extrem hoher Wahrscheinlichkeit nicht heran. Dummerweise kommen auch Berechtigte an die Daten nur unter größeren Mühen heran. Außerdem sind solche Sicherheitsmaßnahmen auch entsprechend teuer.
Das zu erzielende Sicherheitsniveau ist daher immer auch von der wirtschaftlichen Betrachtungsweise abhängig. Daten für fünfzig Cent abzusichern mit einem System für hunderttausend Euro ist garantiert unsinniger Overkill.
Daten so abzusichern, dass man auch als Berechtigter kaum drankommt, ist unsinnig, wenn die Bequemlichkeit nicht zu stark eingeschränkt werden darf. Überlege dir nur mal, wie viele Kunden ein Internetshop finden würde, wenn man vor dem Kauf erst per PostIdent den Account beantragen muß, und in den man sich nur einloggen kann, wenn man einen Chipkartenleser mit kryptographischer Chipkarte an seinen PC anschließt - und das alles nur, damit Angreifer nicht an eventuell eingetragene Kontodaten oder Kreditkartennummern gelangen können.
Natürlich sollte man deshalb nicht leichtfertig Sicherheit verschenken, wenn man sie nahezu kostenlos haben kann, und sie keine Beeinträchtigung der Nutzer darstellt. Andererseits habe ich bei sehr vielen diesbezüglichen Fragen den Eindruck, dass der Fragesteller einfach nur eine unbestimmte Angst hat, irgendetwas Unsicheres zu programmieren - und in Wirklichkeit sind Daten im Wert von 50 Cent bedroht.
- Sven Rautenberg
--
"Love your nation - respect the others."