Grundlagen der Session-Verwaltung
Session-Sicherheit
Das Session-Modul kann nicht garantieren, dass die in einer Session gespeicherten Informationen nur von dem Benutzer eingesehen werden können, der die Session erstellt hat. Es sind zusätzliche Maßnahmen erforderlich, um die Vertraulichkeit der Session zu schützen, je nach dem, welcher Wert mit ihr verbunden ist.
Die Wichtigkeit der Daten, die in der Session enthalten sind, muss
bewertet werden und weitere Schutzmaßnahmen können erforderlich sein; dies
hat in der Regel einen Preis, z. B. einen geringeren Komfort für den
Benutzer. Um den Benutzer zum Beispiel vor einer einfachen Taktik des
Social Engineering (Sozialmanipulation, Ausnutzung menschlicher Schwächen)
zu schützen, muss session.use_only_cookies
aktiviert
werden. In diesem Fall müssen auf der Client-Seite unbedingt Cookies
erlaubt sein, sonst funktionieren die Sessions nicht.
Es gibt mehrere Wege, eine bestehende Session-ID an Dritte durchsickern zu lassen, z. B. JavaScript-Injections, Session-IDs in URLs, Packet Sniffing, physischer Zugriff auf das Gerät etc. Eine durchgesickerte Session-ID ermöglicht Dritten, auf alle Ressourcen zuzugreifen, die mit einer bestimmten ID verbunden sind. Erstens: URLs, die die Session-IDs enthalten. Wenn es Links zu einer externen Seite oder Ressource gibt, kann die URL einschließlich der Session-ID in den Referrer-Protokollen der externen Seite gespeichert werden. Zweitens: Ein aktiverer Angreifer könnte den Netzwerkverkehr abhören. Wenn dieser unverschlüsselt ist, fließen die Session-IDs im Klartext über das Netzwerk. Die Lösung ist, SSL/TLS auf dem Server zu implementieren und für die Benutzer obligatorisch zu machen. Für eine verbesserte Sicherheit sollte HSTS verwendet werden.
Hinweis: Auch HTTPS kann vertrauliche Daten nicht immer schützen. Zum Beispiel können die Sicherheitslücken CRIME und Beast einem Angreifer ermöglichen, die Daten zu lesen. Zu beachten ist auch, dass viele Netzwerke HTTPS-MITM-Proxys zu Prüfzwecken einsetzen. Angreifer können ebenfalls einen solchen Proxy einrichten.
Nicht-adaptive Session-Verwaltung
Der Session-Verwalter von PHP ist derzeit standardmäßig adaptiv. Ein adaptiver Session-Verwalter birgt zusätzliche Risiken.
Wenn
session.use_strict_mode
aktiviert ist und die Session-Speicherroutine dies unterstützt, wird eine
uninitialisierte Session-ID verworfen und eine neue erstellt. Dies
verhindert einen Angriff, der Benutzer dazu zwingt, eine bereits bekannte
Session-ID zu verwenden. Ein Angreifer könnte Links einfügen oder E-Mails
senden, die die Session-ID enthalten, z. B.
http://example.com/page.php?PHPSESSID=123456789
. Wenn
session.use_trans_sid
aktiviert ist, startet das Opfer damit eine Session mit der vom Angreifer
angegebenen Session-ID.
session.use_strict_mode
entschärft dieses Risiko.
Benutzerdefinierte Speicherroutinen können den strikten Session-Modus ebenfalls unterstützen, indem sie eine Validierung der Session-ID implementieren. Alle benutzerdefinierten Speicherroutinen sollten eine Validierung der Session-ID implementieren.
Das Cookie für die Session-ID kann mit den Attributen domain, path, httponly, secure und ab PHP 7.3 mit dem Attribut SameSite gesetzt werden. Es gibt eine von den Browsern definierte Vorrangigkeit. Durch das Ausnutzen der Rangfolge kann ein Angreifer eine Session-ID setzen, die dauerhaft verwendet werden kann. Die Verwendung von session.use_only_cookies wird dieses Problem nicht lösen. session.use_strict_mode entschärft dieses Risiko. Mit session.use_strict_mode=On wird die nicht initialisierte Session-ID abgelehnt.
Hinweis: Auch wenn session.use_strict_mode das Risiko der adaptiven Session-Verwaltung abschwächt, kann ein Angreifer die Benutzer dazu bringen, eine initialisierte Session-ID zu verwenden, die von ihm erstellt wurde, z. B. durch eine JavaScript-Injection. Dieser Angriff kann durch die Empfehlungen dieses Handbuchs entschärft werden. Wenn Entwickler dieses Handbuch befolgen, sollten sie session.use_strict_mode aktivieren, die zeitstempelbasierte Session-Verwaltung verwenden und die Session-IDs mittels session_regenerate_id() mit den empfohlenen Verfahren neu erzeugen. Folgen Entwickler allen oben genannten Punkten, wird eine von einem Angreifer generierte Session-ID letztlich gelöscht werden. Wenn ein Zugriff auf eine veraltete Session erfolgt, sollten Entwickler alle aktiven Session-Daten des Benutzers speichern, da diese Informationen für eine anschließende Untersuchung relevant sind. Der Benutzer sollte zwangsweise von allen Sessions abgemeldet werden, d. h. er muss sich neu authentifizieren. Dies verhindert, dass Angreifer gestohlene Sessions missbrauchen können.
Der Zugriff auf eine veraltete Session deutet nicht unbedingt auf einen Angriff hin. Ein instabiles Netzwerk und/oder die sofortige Löschung der aktiven Session kann dazu führen, dass legitime Benutzer veraltete Sessions verwenden.
Ab PHP 7.1.0 wurde session_create_id() hinzugefügt. Diese Funktion kann verwendet werden, um effizient auf alle aktiven Sessions eines Benutzers zuzugreifen, indem den Session-IDs die Benutzer-ID vorangestellt wird. Die Aktivierung von session.use_strict_mode ist bei dieser Einrichtung unbedingt erforderlich. Andernfalls können böswillige Benutzer schädliche Session-IDs für andere Benutzer setzen.
Hinweis: Vor PHP 7.1.0 sollten Benutzer einen CSPRNG (kryptographisch SICHEREN Zufallszahlengenerator) verwenden, um eine neue Session-ID zu erzeugen, z. B. /dev/urandom oder random_bytes() und Hash-Funktionen. session_create_id() hat eine Kollisionserkennung und erzeugt eine Session-ID gemäß den INI-Einstellungen für Sessions. Die Verwendung von session_create_id() wird hier empfohlen.
Erneuern von Session-IDs
Die Anweisung session.use_strict_mode ist ein guter erster Schritt, reicht aber nicht aus. Für die Sicherheit von Sessions sollten Entwickler auch die Funktion session_regenerate_id() verwenden.
Das Erneuern einer Session-ID reduziert das Risiko von gestohlenen Session-IDs, daher sollte die Funktion session_regenerate_id() regelmäßig aufgerufen werden; z. B. sollte die Session-ID für sicherheitsrelevante Inhalte alle 15 Minuten neu generiert werden. Selbst für den Fall, dass eine Session-ID gestohlen wird, läuft die Session sowohl beim legitimen Benutzer als auch beim Angreifer ab. Mit anderen Worten: Der Zugriff auf den Inhalt, entweder durch den Benutzer oder den Angreifer, erzeugt beim Zugriff auf eine veraltete Session einen Fehler.
Session-IDs müssen neu generiert werden, wenn die Berechtigungen des Benutzers erhöht werden, z. B. nach einer Authentifizierung. Die Funktion session_regenerate_id() muss aufgerufen werden, bevor die Authentifizierungsinformationen in $_SESSION gespeichert werden (session_regenerate_id() speichert die aktuellen Session-Daten automatisch, um Zeitstempel/etc. in der aktuellen Session zu speichern). Stellen Sie sicher, dass nur die neue Session das Authentifizierungsflag enthält.
Entwickler dürfen sich nicht auf den Ablauf der Session-ID durch session.gc_maxlifetime verlassen. Angreifer können in regelmäßigen Abständen auf die Session-ID eines Opfers zugreifen, um deren Ablauf zu verhindern und sie weiter auszunutzen, unter anderem auch bei einer authentifizierten Session.
Stattdessen müssen Entwickler eine zeitstempelbasierte Session-Datenverwaltung implementieren.
Obwohl der Session-Verwalter Zeitstempel transparent verwalten kann, ist
diese Funktion nicht implementiert. Alte Session-Daten müssen bis zur GC
aufbewahrt werden. Gleichzeitig müssen die Entwickler sicherstellen, dass
veraltete Session-Daten entfernt werden. Allerdings dürfen Entwickler
aktive Session-Daten nicht sofort entfernen, d. h.
session_regenerate_id(true);
und
session_destroy() dürfen niemals zusammen für eine
aktive Session aufgerufen werden. Dies mag widersprüchlich klingen, ist
aber eine zwingende Voraussetzung.
session_regenerate_id() löscht veraltete Sessions standardmäßig nicht. Veraltete authentifizierte Sessions können zur weiteren Verwendung vorhanden sein. Entwickler müssen daher sicherstellen, dass veraltete Sessions von niemandem genutzt werden können. Sie müssen den Zugriff auf veraltete Session-Daten selbst mit Zeitstempeln verhindern.
Das plötzliche Entfernen einer aktiven Session erzeugt unerwünschte Nebeneffekte. Sessions können verschwinden, wenn es gleichzeitige Verbindungen zur Webanwendung gibt und/oder das Netzwerk instabil ist.
Potenziell böswillige Zugriffe sind durch das plötzliche Entfernen aktiver Sessions nicht zu erkennen.
Anstatt veraltete Sessions sofort zu löschen, müssen Entwickler eine kurzfristige Verfallszeit (Zeitstempel) in $_SESSION setzen, die den Zugriff auf die Session-Daten verhindert.
Entwickler dürfen den Zugriff auf alte Session-Daten nicht sofort nach session_regenerate_id() verbieten. Das muss zu einem späteren Zeitpunkt erfolgen, d. h. ein paar Sekunden später bei stabilen Netzwerken, z. B. einem kabelgebundenen Netzwerk, und ein paar Minuten später bei instabilen Netzwerken, z. B. einem Mobiltelefon oder Wi-Fi.
Wenn ein Benutzer auf eine veraltete (abgelaufene) Session zugreift, sollte der Zugriff auf diese verweigert werden. Es wird auch empfohlen, den Status "authentifiziert" aus allen Sessions des Benutzers zu entfernen, da es sich wahrscheinlich um einen Angriff handelt.
Die korrekte Verwendung von session.use_only_cookies und session_regenerate_id() kann einen persönlichen DoS mit nicht löschbaren Cookies verursachen, die von Angreifern gesetzt wurden. In diesem Fall können die Entwickler die Benutzer auffordern, die Cookies zu entfernen und sie darauf hinweisen, dass sie von einem Sicherheitsproblem betroffen sein könnten. Angreifer können bösartige Cookies über eine anfällige Webanwendung setzen, über ein ungeschütztes/schädliches Browser-Plugin, über ein physisch kompromittiertes Gerät usw.
Unterschätzen Sie das DoS-Risiko nicht.
use_strict_mode=On
ist für die allgemeine Sicherheit
der Session-ID zwingend erforderlich! Allen Webseiten wird empfohlen
use_strict_mode
zu aktivieren.
Ein DoS kann nur auftreten, wenn das Konto angegriffen wird. Eine durch JavaScript verursachte Sicherheitslücke in einer Anwendung ist die häufigste Ursache.
Löschen der Session-Daten
Veraltete Session-Daten müssen unzugänglich gemacht und gelöscht werden. Das aktuelle Session-Modul kann dies nicht gut handhaben.
Veraltete Session-Daten sollten so schnell wie möglich entfernt werden. Aktive Sessions dürfen jedoch nicht sofort entfernt werden. Um diese Anforderungen zu erfüllen, müssen die Entwickler eine auf Zeitstempel basierende Session-Datenverwaltung selbst implementieren.
Setzen und verwalten Sie den Ablaufzeitstempel in $_SESSION. Verbieten Sie den Zugriff auf veraltete Session-Daten. Wenn der Zugriff auf veraltete Session-Daten festgestellt wird, ist es ratsam, den kompletten Authentifizierungsstatus aus den Sessions des Benutzers zu entfernen und ihn zu zwingen, sich erneut zu authentifizieren. Der Zugriff auf veraltete Session-Daten kann einen Angriff darstellen. Um dies zu verhindern, müssen die Entwickler alle aktiven Sessions jedes Benutzers verfolgen.
Hinweis: Der Zugriff auf eine veraltete Session kann auch aufgrund eines instabilen Netzwerks und/oder konkurrierende Zugriffe auf die Website erfolgen. Der Server hat z. B. versucht, eine neue Session-ID über ein Cookie zu setzen, aber das betreffende Set-Cookie-Paket hat den Client möglicherweise aufgrund eines Verbindungsverlusts nicht erreicht. Eine Verbindung kann eine neue Session-ID per session_regenerate_id() ausgeben, aber eine andere gleichzeitige Verbindung hat die neue Session-ID möglicherweise noch nicht erhalten. Daher müssen die Entwickler den Zugriff auf die veraltete Session zu einem späteren Zeitpunkt verhindern. Das heißt, eine zeitstempelbasierte Session-Verwaltung zwingend ist erforderlich.
Zusammenfassend lässt sich sagen, dass Session-Daten weder mit session_regenerate_id() noch mit session_destroy() zerstört werden dürfen, sondern es müssen Zeitstempel verwendet werden, um den Zugriff auf die Session-Daten zu kontrollieren. Lassen Sie session_gc() veraltete Daten aus dem Session-Datenspeicher entfernen.
Session und Sperren
Session-Daten sind standardmäßig gesperrt, um Race Conditions zu vermeiden. Das Sperren ist zwingend erforderlich, um Session-Daten über Anfragen hinweg konsistent zu halten.
Die Session-Sperrung kann jedoch von Angreifern missbraucht werden, um
DoS-Angriffe durchzuführen. Halten Sie Sperren möglichst gering, um das
Risiko eines DoS-Angriffs durch die Session-Sperrung zu minimieren.
Verwenden Sie schreibgeschützte Sessions, wenn die Session-Daten nicht
aktualisiert werden müssen. Verwenden Sie bei der Funktion
session_start() die Option "read_and_close":
session_start(['read_and_close'=>1]);
. Schließen Sie
die Session, nachdem Sie $_SESSION aktualisiert haben, so schnell wie
möglich mit session_commit().
Das aktuelle Session-Modul erkennt keinerlei Änderungen an $_SESSION, wenn die Session inaktiv ist. Es liegt in der Verantwortung des Entwicklers, $_SESSION nicht zu verändern, während die Session inaktiv ist.
Aktive Sessions
Die Entwickler sollten alle aktiven Sessions für jeden Benutzer im Auge behalten und sie darüber informieren, wie viele Sessions aktiv sind, von welcher IP-Adresse, wie lange usw. PHP speichert diese Informationen nicht. Die Entwickler sollen dies selbst tun.
Es gibt mehrere Möglichkeiten, dies zu implementieren. Eine Möglichkeit besteht darin, eine Datenbank zu definieren, die die erforderlichen Daten verwaltet, und alle relevanten Informationen darin zu speichern. Da die Session-Daten mit einer GC verbunden sind, müssen die Entwickler auf die GC-Daten achten, um die Datenbank der aktiven Sessions konsistent zu halten.
Eine einfache Implementierung besteht darin, die Benutzer-ID als Präfix vor die Session-ID zu setzen und die notwendigen Informationen in der Variablen $_SESSION zu speichern. Die meisten Datenbanken sind relativ gut darin, ein Präfix als Zeichenkette auszuwählen. Entwickler KÖNNEN hierfür sowohl die Funktion session_regenerate_id() als auch die Funktion session_create_id() verwenden.
Verwenden Sie niemals vertrauliche Daten als Präfix. Wenn die Benutzer-ID geheim ist, erwägen Sie die Verwendung von hash_hmac().
Das Aktivieren von session.use_strict_mode ist für diese Konfiguration zwingend erforderlich. Stellen Sie sicher, dass es aktiviert ist. Andernfalls kann die aktive Session-Datenbank kompromittiert werden.
Die zeitstempelbasierte Session-Verwaltung ist zwingend erforderlich, um den Zugriff auf veraltete Sessions zu erkennen. Wenn der Zugriff auf eine veraltete Session erkannt wird, sollten die Authentifizierungsflags aus allen aktiven Sessions des Benutzers entfernt werden. Dies verhindert, dass Angreifer weiterhin gestohlene Sessions ausnutzen können.
Session und automatische Anmeldung
Entwickler dürfen keine langlebigen Session-IDs für automatische Anmeldungen verwenden, da dies das Risiko von gestohlenen Sessions erhöht. Die Funktionalität für eine automatische Anmeldung sollte vom Entwickler implementiert werden.
Verwenden Sie mithilfe der Funktion setcookie() einen sicheren, einmaligen Hash-Schlüssel als Schlüssel für die automatische Anmeldung. Verwenden Sie einen sicheren Hash, der stärker ist als SHA-2, z. B. SHA-256 oder höher, mit Zufallsdaten aus random_bytes() oder /dev/urandom.
Wenn der Benutzer nicht authentifiziert ist, prüfen Sie, ob der einmalige Schlüssel für die automatische Anmeldung gültig ist oder nicht. Falls er gültig ist, authentifizieren Sie den Benutzer und setzen Sie einen neuen sicheren Einmal-Hash-Schlüssel. Ein Schlüssel für eine automatische Anmeldung darf nur einmal verwendet werden, d. h. verwenden Sie einen solchen Schlüssel niemals mehrfach, sondern erzeugen Sie immer einen neuen.
Ein Schlüssel für eine automatische Anmeldung ist ein Authentifizierungsschlüssel mit langer Lebensdauer, er sollte so gut wie möglich geschützt werden. Verwenden Sie die Cookie-Attribute path/httponly/secure/SameSite, um ihn zu schützen, d. h. übertragen Sie den Schlüssel für die automatische Anmeldung nie, wenn es nicht erforderlich ist.
Der Entwickler muss die Funktionalität implementieren, die die automatische Anmeldung deaktivieren und das nicht benötigte Cookie für die automatische Anmeldung entfernen.
CSRF-Angriffe (Cross-Site Request Forgeries)
Sessions und Authentifizierung schützen nicht vor CSRF-Angriffen. Entwickler müssen den CSRF-Schutz selbst implementieren.
output_add_rewrite_var() kann für den CSRF-Schutz verwendet werden. Weitere Details sind auf der entsprechenden Handbuchseite zu finden.
Hinweis: PHP verwendet vor Version 7.2.0 denselben Ausgabepuffer und dieselbe INI-Einstellung wie trans-sid. Daher ist die Verwendung von output_add_rewrite_var() in PHP vor Version 7.2.0 nicht empfohlen.
Die meisten Webanwendungs-Frameworks unterstützen einen Schutz gegen CSRF. Weitere Details sind im Handbuch des Webanwendungs-Frameworks zu finden.
Ab PHP 7.3 kann das SameSite-Attribut für das Session-Cookie gesetzt werden. Dies ist eine zusätzliche Maßnahme, die CSRF-Schwachstellen entschärfen kann.