Sitzungs-ID-Schutz in PHP. Fallstricke bei der Verwendung von Sitzungen in PHP Übergeben eines Werts oder Arrays mithilfe einer PHP-Sitzung

Liebe Grüße, liebe Community.

Zunächst möchte ich Ihnen für die sehr nützliche Ressource danken. Mehr als einmal habe ich hier viele interessante Ideen und praktische Ratschläge gefunden.

Der Zweck dieses Artikels besteht darin, die Fallstricke bei der Verwendung von Sitzungen in PHP hervorzuheben. Natürlich gibt es eine PHP-Dokumentation und zahlreiche Beispiele, und dieser Artikel erhebt keinen Anspruch auf Vollständigkeit. Es soll einige Nuancen der Arbeit mit Sitzungen offenbaren und Entwickler vor unnötiger Zeitverschwendung schützen.

Das häufigste Beispiel für die Verwendung von Sitzungen ist natürlich die Benutzerautorisierung. Beginnen wir mit der grundlegendsten Implementierung, um sie schrittweise weiterzuentwickeln, wenn neue Aufgaben entstehen.

(Um Platz und Zeit zu sparen, beschränken wir unsere Beispiele nur auf die Sitzungsfunktionen selbst, anstatt hier eine vollwertige Testanwendung mit einer schönen Klassenhierarchie, umfassender Fehlerbehandlung und anderen guten Dingen zu erstellen.)

Funktion startSession() ( // Wenn die Sitzung bereits gestartet wurde, stoppen Sie die Ausführung und geben Sie TRUE zurück // (der Parameter session.auto_start in der Einstellungsdatei php.ini muss deaktiviert sein – der Standardwert), wenn (session_id()) zurückgegeben wird true; else return session_start(); // Hinweis: Vor Version 5.3.0 gab die Funktion session_start() TRUE zurück, auch wenn ein Fehler auftrat. // Wenn Sie eine Version vor 5.3.0 verwenden, führen Sie eine zusätzliche Prüfung durch for session_id() // nach dem Aufruf von session_start() ) function destroySession() ( if (session_id()) ( // Wenn eine aktive Sitzung vorhanden ist, löschen Sie die Sitzungscookies, setcookie(session_name(), session_id(), time( )-60*60*24); // und die Sitzung zerstören session_unset( ); session_destroy(); ) )

Hinweis: Es wird davon ausgegangen, dass der Leser über Grundkenntnisse in PHP-Sitzungen verfügt, daher werden wir hier nicht auf die Funktionsweise der Funktionen session_start() und session_destroy() eingehen. Die Aufgaben des Layouts des Anmeldeformulars und der Benutzerauthentifizierung haben nichts mit dem Thema des Artikels zu tun, daher werden wir sie auch weglassen. Ich möchte Sie nur daran erinnern, dass wir zur Identifizierung des Benutzers bei jeder nachfolgenden Anfrage im Moment der erfolgreichen Anmeldung die Benutzerkennung in einer Sitzungsvariablen (z. B. mit dem Namen „userid“) speichern müssen, die in allen nachfolgenden Anfragen verfügbar ist das Leben der Sitzung. Es ist auch notwendig, die Verarbeitung des Ergebnisses unserer Funktion startSession() zu implementieren. Wenn die Funktion FALSE zurückgibt, zeigen Sie das Anmeldeformular im Browser an. Wenn die Funktion TRUE zurückgegeben hat und eine Sitzungsvariable vorhanden ist, die die Kennung des autorisierten Benutzers (in unserem Fall die Benutzer-ID) enthält, zeigen Sie die Seite des autorisierten Benutzers an (weitere Informationen zur Fehlerbehandlung finden Sie in der Ergänzung vom 06.2013). 07 im Abschnitt über Sitzungsvariablen).

Bisher ist alles klar. Fragen beginnen, wenn Sie eine Benutzerinaktivitätskontrolle (Sitzungs-Timeout) implementieren, mehreren Benutzern die gleichzeitige Arbeit in einem Browser ermöglichen und Sitzungen vor unbefugter Nutzung schützen müssen. Dies wird weiter unten besprochen.

Kontrolle der Benutzerinaktivität mithilfe integrierter PHP-Tools Die erste Frage, die sich bei Entwicklern verschiedener Konsolen für Benutzer häufig stellt, ist die automatische Beendigung der Sitzung bei Inaktivität des Benutzers. Es gibt nichts Einfacheres, als dies mithilfe der integrierten Funktionen von PHP zu tun. (Diese Option ist nicht besonders zuverlässig oder flexibel, wir werden sie jedoch der Vollständigkeit halber in Betracht ziehen.)

Funktion startSession() ( // Zeitüberschreitung bei Benutzerinaktivität (in Sekunden) $sessionLifetime = 300; if (session_id()) return true; // Legt die Cookie-Lebensdauer fest ini_set("session.cookie_lifetime", $sessionLifetime); // Wenn Benutzer Inaktivitäts-Timeout ist festgelegt, legen Sie die Sitzungslebensdauer auf dem Server fest // Hinweis: Für einen Produktionsserver wird empfohlen, diese Parameter in der php.ini-Datei voreinzustellen, wenn ($sessionLifetime) ini_set("session.gc_maxlifetime", $sessionLifetime) ; if (session_start( )) ( setcookie(session_name(), session_id(), time()+$sessionLifetime); return true; ) else return false; )

Ein paar Klarstellungen. Wie Sie wissen, bestimmt PHP anhand des Cookie-Namens, der vom Browser im Anforderungsheader gesendet wird, welche Sitzung gestartet werden muss. Der Browser wiederum empfängt dieses Cookie vom Server, wo es von der Funktion session_start() platziert wird. Wenn das Browser-Cookie abgelaufen ist, wird es nicht in der Anfrage gesendet, was bedeutet, dass PHP nicht bestimmen kann, welche Sitzung gestartet werden soll, und dies als Erstellung einer neuen Sitzung behandelt. Der PHP-Einstellungsparameter session.gc_maxlifetime, der unserem Benutzerinaktivitäts-Timeout entspricht, legt die Lebensdauer einer PHP-Sitzung fest und wird vom Server gesteuert. Die Steuerung der Sitzungslebensdauer funktioniert wie folgt (hier betrachten wir ein Beispiel für das Speichern von Sitzungen in temporären Dateien als die häufigste und standardmäßige Option in PHP).

Wenn eine neue Sitzung erstellt wird, wird eine Datei mit dem Namen sess_ in dem Verzeichnis erstellt, das im PHP-Einstellungsparameter session.save_path als Verzeichnis zum Speichern von Sitzungen festgelegt ist. Dabei handelt es sich um die Sitzungskennung. Als nächstes aktualisiert PHP bei jeder Anfrage beim Starten einer bereits vorhandenen Sitzung die Änderungszeit dieser Datei. Somit kann PHP bei jeder nachfolgenden Anfrage anhand der Differenz zwischen der aktuellen Zeit und der Zeit der letzten Änderung der Sitzungsdatei feststellen, ob die Sitzung aktiv ist oder ihre Lebensdauer bereits abgelaufen ist. (Der Mechanismus zum Löschen alter Sitzungsdateien wird im nächsten Abschnitt ausführlicher erläutert.)

Hinweis: Hierbei ist zu beachten, dass der Parameter session.gc_maxlifetime für alle Sitzungen innerhalb eines Servers (genauer gesagt innerhalb eines Haupt-PHP-Prozesses) gilt. In der Praxis bedeutet dies, dass, wenn mehrere Sites auf dem Server ausgeführt werden und jede von ihnen über ein eigenes Zeitlimit für Benutzerinaktivität verfügt, die Einstellung dieses Parameters auf einer der Sites dazu führt, dass er auch für andere Sites festgelegt wird. Gleiches gilt für Shared Hosting. Um diese Situation zu vermeiden, werden für jede Site innerhalb desselben Servers separate Sitzungsverzeichnisse verwendet. Das Festlegen des Pfads zum Sitzungsverzeichnis erfolgt über den Parameter session.save_path in der Einstellungsdatei php.ini oder durch Aufrufen der Funktion ini_set(). Danach werden die Sitzungen jeder Site in separaten Verzeichnissen gespeichert und der auf einer der Sites festgelegte Parameter session.gc_maxlifetime ist nur für die jeweilige Sitzung gültig. Auf diesen Fall gehen wir nicht näher ein, zumal uns eine flexiblere Möglichkeit zur Überwachung der Benutzerinaktivität zur Verfügung steht.

Kontrolle der Benutzerinaktivität mithilfe von Sitzungsvariablen Es scheint, dass die vorherige Option trotz ihrer Einfachheit (nur ein paar zusätzliche Codezeilen) alles bietet, was wir brauchen. Was aber, wenn nicht jede Anfrage als Ergebnis einer Nutzeraktivität betrachtet werden kann? Beispielsweise verfügt eine Seite über einen Timer, der regelmäßig eine AJAX-Anfrage stellt, um Aktualisierungen vom Server zu erhalten. Eine solche Anfrage kann nicht als Benutzeraktivität betrachtet werden, was bedeutet, dass eine automatische Verlängerung der Sitzungsdauer in diesem Fall nicht korrekt ist. Wir wissen jedoch, dass PHP die Änderungszeit der Sitzungsdatei jedes Mal automatisch aktualisiert, wenn die Funktion session_start() aufgerufen wird, was bedeutet, dass jede Anfrage zu einer Verlängerung der Sitzungslebensdauer führt und es nie zu einem Timeout bei Benutzerinaktivität kommt. Darüber hinaus mag der letzte Hinweis aus dem vorherigen Abschnitt zu den Feinheiten des Parameters session.gc_maxlifetime für manche zu verwirrend und schwierig zu implementieren erscheinen.

Um dieses Problem zu lösen, verzichten wir auf die Verwendung integrierter PHP-Mechanismen und führen mehrere neue Sitzungsvariablen ein, die es uns ermöglichen, die Zeit der Benutzerinaktivität selbst zu steuern.

Funktion startSession($isUserActivity=true) ( ​​​​$sessionLifetime = 300; if (session_id()) return true; // Legt die Cookie-Lebensdauer fest, bevor der Browser geschlossen wird (wir steuern alles auf der Serverseite) ini_set("session. cookie_lifetime", 0) ; if (! session_start()) return false; $t = time(); if ($sessionLifetime) ( // Wenn das Benutzerinaktivitäts-Timeout festgelegt ist, // überprüfen Sie die seit der letzten Benutzeraktivität verstrichene Zeit // (letzte Anforderungszeit, als die Lastactivity-Sitzungsvariable aktualisiert wurde) if (isset($_SESSION["lastactivity"]) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( // Wenn die Zeit seitdem verstrichen ist Die letzte Aktivität des Benutzers, / / ​​ist größer als das Inaktivitäts-Timeout, was bedeutet, dass die Sitzung abgelaufen ist und Sie die Sitzung beenden müssen destroySession(); return false; ) else ( // Wenn das Timeout noch nicht eingetreten ist, // und Wenn die Anfrage als Ergebnis einer Benutzeraktivität kam, // aktualisiere die Variable „lastactivity“ mit dem Wert der aktuellen Zeit, // und verlängere dadurch die Sitzungszeit um weitere sessionLifetime-Sekunden, wenn ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) return true; )

Fassen wir zusammen. Bei jeder Anfrage prüfen wir, ob das Timeout seit der letzten Benutzeraktivität bis zum aktuellen Zeitpunkt erreicht wurde. Wenn es erreicht ist, zerstören wir die Sitzung, unterbrechen die Ausführung der Funktion und geben FALSE zurück. Wenn das Timeout nicht erreicht wurde und der Parameter $isUserActivity mit dem Wert TRUE an die Funktion übergeben wird, aktualisieren wir den Zeitpunkt der letzten Aktivität des Benutzers. Wir müssen lediglich im aufrufenden Skript feststellen, ob die Anfrage das Ergebnis einer Benutzeraktivität ist. Wenn nicht, rufen Sie die Funktion startSession auf, wobei der Parameter $isUserActivity auf FALSE gesetzt ist.

Ergänzung vom 07.06.2013 Verarbeitung des Ergebnisses der Funktion sessionStart()

In den Kommentaren wurde darauf hingewiesen, dass die Rückgabe von FALSE kein vollständiges Verständnis der Fehlerursache liefert, und das ist absolut fair. Eine ausführliche Fehlerbehandlung habe ich hier nicht veröffentlicht (die Länge des Artikels ist schon recht groß), da dies nicht direkt mit dem Thema des Artikels zusammenhängt. Aber angesichts der Kommentare werde ich es klarstellen.

Wie Sie sehen, kann die sessionStart-Funktion in zwei Fällen FALSE zurückgeben. Entweder konnte die Sitzung aufgrund einiger interner Serverfehler (z. B. falsche Sitzungseinstellungen in php.ini) nicht gestartet werden, oder die Sitzungsdauer ist abgelaufen. Im ersten Fall müssen wir den Benutzer auf eine Seite mit einer Fehlermeldung umleiten, dass es Probleme auf dem Server gibt, und einem Formular zur Kontaktaufnahme mit dem Support. Im zweiten Fall müssen wir den Benutzer zum Anmeldeformular weiterleiten und dort eine entsprechende Meldung anzeigen, dass die Sitzung abgelaufen ist. Dazu müssen wir Fehlercodes eingeben und den entsprechenden Code anstelle von FALSE zurückgeben und ihn in der aufrufenden Methode überprüfen und entsprechend handeln.

Selbst wenn nun noch eine Sitzung auf dem Server existiert, wird diese beim ersten Zugriff zerstört, wenn das Inaktivitäts-Timeout des Benutzers abgelaufen ist. Und dies geschieht unabhängig davon, welche Sitzungsdauer in den globalen PHP-Einstellungen festgelegt ist.

Hinweis: Was passiert, wenn der Browser geschlossen wurde und das Sitzungsnamen-Cookie automatisch gelöscht wurde? Die Anfrage an den Server beim nächsten Öffnen des Browsers enthält keine Sitzungscookies und der Server kann die Sitzung nicht öffnen und das Inaktivitäts-Timeout des Benutzers nicht überprüfen. Für uns ist dies gleichbedeutend mit dem Anlegen einer neuen Sitzung und hat keinerlei Auswirkungen auf die Funktionalität oder Sicherheit. Es stellt sich jedoch die berechtigte Frage: Wer wird dann die alte Sitzung zerstören, wenn wir sie bisher nach Ablauf des Timeouts zerstört haben? Oder bleibt es jetzt für immer im Sitzungsverzeichnis hängen? Um alte Sitzungen in PHP zu bereinigen, gibt es einen Mechanismus namens Garbage Collection. Es wird zum Zeitpunkt der nächsten Anfrage an den Server ausgeführt und löscht alle alten Sitzungen basierend auf dem letzten Änderungsdatum der Sitzungsdateien. Der Garbage-Collection-Mechanismus startet jedoch nicht bei jeder Anfrage an den Server. Die Häufigkeit (bzw. die Wahrscheinlichkeit) des Starts wird durch zwei Einstellungsparameter session.gc_probability und session.gc_divisor bestimmt. Das Ergebnis der Division des ersten Parameters durch den zweiten ist die Wahrscheinlichkeit, mit der der Garbage-Collection-Mechanismus gestartet wird. Damit der Mechanismus zum Löschen der Sitzung bei jeder Anfrage an den Server gestartet wird, müssen diese Parameter auf gleiche Werte gesetzt werden, beispielsweise „1“. Dieser Ansatz garantiert ein sauberes Sitzungsverzeichnis, ist aber offensichtlich zu teuer für den Server. Daher ist auf Produktionssystemen der Standardwert von session.gc_divisor auf 1000 festgelegt, was bedeutet, dass der Garbage-Collection-Mechanismus mit einer Wahrscheinlichkeit von 1/1000 ausgeführt wird. Wenn Sie mit diesen Einstellungen in Ihrer php.ini-Datei experimentieren, stellen Sie möglicherweise fest, dass im oben beschriebenen Fall, wenn der Browser schließt und alle seine Cookies löscht, noch eine Weile alte Sitzungen im Sitzungsverzeichnis verbleiben. Aber das sollte Sie nicht beunruhigen, denn... Wie bereits erwähnt, beeinträchtigt dies in keiner Weise die Sicherheit unseres Mechanismus.

Update vom 07.06.2013 Verhindert das Einfrieren von Skripten aufgrund der Sperrung von Sitzungsdateien

In den Kommentaren wurde das Problem angesprochen, dass gleichzeitig ausgeführte Skripte aufgrund der Blockierung der Sitzungsdatei einfrieren (die auffälligste Option ist die lange Abfrage).

Zunächst stelle ich fest, dass dieses Problem nicht direkt von der Serverlast oder der Anzahl der Benutzer abhängt. Je mehr Anfragen, desto langsamer werden natürlich die Skripte ausgeführt. Dies ist jedoch eine indirekte Abhängigkeit. Das Problem tritt nur innerhalb einer Sitzung auf, wenn der Server mehrere Anfragen im Namen eines Benutzers erhält (z. B. eine davon ist eine lange Abfrage und der Rest sind reguläre Anfragen). Jede Anfrage versucht, auf dieselbe Sitzungsdatei zuzugreifen. Wenn die vorherige Anfrage die Datei nicht entsperrt hat, bleibt die nachfolgende Anfrage hängen und wartet.

Um die Sperrung der Sitzungsdatei auf ein Minimum zu beschränken, wird dringend empfohlen, die Sitzung durch Aufrufen der Funktion session_write_close() unmittelbar nach Abschluss aller Aktionen mit Sitzungsvariablen zu schließen. In der Praxis bedeutet dies, dass Sie nicht alles in Sitzungsvariablen speichern und während der Ausführung des Skripts darauf zugreifen sollten. Und wenn Sie einige Arbeitsdaten in Sitzungsvariablen speichern müssen, lesen Sie diese sofort beim Start der Sitzung, speichern Sie sie zur späteren Verwendung in lokalen Variablen und schließen Sie die Sitzung (d. h. die Sitzung wird mit der Funktion „session_write_close“ geschlossen und nicht mit „session_destroy“ zerstört). ).

In unserem Beispiel bedeutet dies, dass wir unmittelbar nach dem Öffnen einer Sitzung, der Überprüfung ihrer Lebensdauer und der Existenz eines autorisierten Benutzers alle zusätzlichen Sitzungsvariablen lesen und speichern müssen, die von der Anwendung benötigt werden (falls vorhanden), und dann die Sitzung mit einem Aufruf von schließen müssen session_write_close() und setzen Sie die Ausführung eines Skripts fort, sei es eine lange Abfrage oder eine reguläre Anfrage.

Sitzungen vor unbefugter Nutzung schützen Stellen wir uns eine Situation vor. Einer Ihrer Benutzer erhält einen Trojaner, der die Browser-Cookies (in denen unsere Sitzung gespeichert ist) raubt und an die angegebene E-Mail-Adresse sendet. Der Angreifer erhält das Cookie und verwendet es, um eine Anfrage im Namen unseres autorisierten Benutzers zu fälschen. Der Server akzeptiert und verarbeitet diese Anfrage erfolgreich, als käme sie von einem autorisierten Benutzer. Wenn keine zusätzliche Überprüfung der IP-Adresse durchgeführt wird, führt ein solcher Angriff zu einem erfolgreichen Hacking des Benutzerkontos mit allen daraus resultierenden Konsequenzen.

Warum war das möglich? Da der Name und die Sitzungskennung während der gesamten Lebensdauer der Sitzung immer gleich sind und Sie diese Daten erhalten, können Sie problemlos Anfragen im Namen eines anderen Benutzers senden (natürlich innerhalb der Lebensdauer dieser Sitzung). Dies ist möglicherweise nicht die häufigste Angriffsart, scheint aber theoretisch durchaus machbar, insbesondere wenn man bedenkt, dass ein solcher Trojaner nicht einmal Administratorrechte benötigt, um die Browser-Cookies des Benutzers zu stehlen.

Wie kann man sich vor solchen Angriffen schützen? Auch hier gilt natürlich, dass die Lebensdauer der Sitzungskennung begrenzt wird und die Kennung innerhalb derselben Sitzung regelmäßig geändert wird. Wir können den Namen der Sitzung auch ändern, indem wir die alte vollständig löschen und eine neue Sitzung erstellen, indem wir alle Sitzungsvariablen aus der alten in diese kopieren. Dies hat jedoch keinen Einfluss auf das Wesentliche des Ansatzes. Der Einfachheit halber beschränken wir uns daher nur auf die Sitzungskennung.

Es ist klar, dass je kürzer die Lebensdauer der Sitzungs-ID ist, desto weniger Zeit hat ein Angreifer, Cookies abzurufen und zu verwenden, um eine Benutzeranfrage zu fälschen. Idealerweise sollte für jede Anfrage eine neue Kennung verwendet werden, wodurch die Möglichkeit minimiert wird, die Sitzung einer anderen Person zu verwenden. Wir betrachten jedoch den allgemeinen Fall, bei dem die Regenerationszeit der Sitzungskennung willkürlich festgelegt wird.

(Wir werden den Teil des Codes weglassen, der bereits besprochen wurde).

Funktion startSession($isUserActivity=true) ( ​​​​// Lebensdauer der Sitzungskennung $idLifetime = 60; ... if ($idLifetime) ( // Wenn die Lebensdauer der Sitzungskennung festgelegt ist, // überprüfen Sie die seit der Sitzung verstrichene Zeit erstellt oder die letzte Regeneration // (Zeit der letzten Anfrage, als die Sitzungsvariable starttime aktualisiert wurde) if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $ idLifetime) ( // Zeit, in der die Lebensdauer des Sitzungsbezeichners abgelaufen ist // Einen neuen Bezeichner generieren session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( // Wir kommen hierher, wenn die Sitzung gerade abgelaufen ist wurde erstellt // Setze die Zeit für die Generierung der Sitzungskennung auf die aktuelle Zeit $_SESSION["starttime"] = $t; ) ) return true; )

Wenn wir also eine neue Sitzung erstellen (was geschieht, wenn sich der Benutzer erfolgreich anmeldet), setzen wir die Sitzungsvariable starttime, die für uns die Zeit der letzten Generierung der Sitzungskennung speichert, auf einen Wert, der der aktuellen Serverzeit entspricht. Als nächstes prüfen wir bei jeder Anfrage, ob seit der letzten Generierung des Identifikators genügend Zeit (idLifetime) vergangen ist, und wenn ja, generieren wir einen neuen. Wenn also während der festgelegten Lebensdauer der Kennung der Angreifer, der das Cookie des autorisierten Benutzers erhalten hat, keine Zeit hat, es zu verwenden, wird die gefälschte Anfrage vom Server als nicht autorisiert betrachtet und der Angreifer wird zur Anmeldeseite weitergeleitet .

Hinweis: Die neue Sitzungs-ID gelangt in das Cookie des Browsers, wenn die Funktion session_regenerate_id() aufgerufen wird, die das neue Cookie sendet, ähnlich wie die Funktion session_start(), sodass wir das Cookie nicht selbst aktualisieren müssen.

Wenn wir unsere Sitzungen so sicher wie möglich machen möchten, reicht es aus, die Lebensdauer des Bezeichners auf eins zu setzen oder sogar die Funktion session_regenerate_id() aus Klammern zu entfernen und alle Prüfungen zu entfernen, was zur Neugenerierung des Bezeichners in jeder Sitzung führt Anfrage. (Ich habe die Auswirkungen dieses Ansatzes auf die Leistung nicht getestet und kann nur sagen, dass die Funktion session_regenerate_id(true) im Wesentlichen nur vier Aktionen ausführt: Generieren eines neuen Bezeichners, Erstellen eines Headers mit dem Sitzungscookie, Löschen des alten und Erstellen eine neue Sitzungsdatei).

Lyrischer Exkurs: Wenn sich der Trojaner als so schlau herausstellt, dass er keine Cookies an den Angreifer sendet, sondern sofort nach Erhalt des Cookies den Versand einer vorbereiteten gefälschten Anfrage organisiert, wird die oben beschriebene Methode höchstwahrscheinlich nicht dazu in der Lage sein Schützen Sie sich vor einem solchen Angriff, da zwischen dem Empfang des Cookies durch den Trojaner und dem Senden einer gefälschten Anfrage praktisch kein Unterschied besteht und die Wahrscheinlichkeit hoch ist, dass die Sitzungskennung zu diesem Zeitpunkt nicht neu generiert wird.

Möglichkeit der gleichzeitigen Arbeit in einem Browser für mehrere Benutzer Die letzte Aufgabe, die ich berücksichtigen möchte, ist die Möglichkeit der gleichzeitigen Arbeit in einem Browser für mehrere Benutzer. Diese Funktion ist besonders in der Testphase nützlich, wenn Sie die gleichzeitige Arbeit von Benutzern emulieren müssen. Es empfiehlt sich, dies in Ihrem Lieblingsbrowser zu tun, anstatt das gesamte verfügbare Arsenal zu verwenden oder mehrere Instanzen des Browsers im Inkognito-Modus zu öffnen .

In unseren vorherigen Beispielen haben wir keinen Sitzungsnamen explizit angegeben, daher wurde der Standard-PHP-Name (PHPSESSID) verwendet. Das bedeutet, dass alle bisher von uns erstellten Sitzungen ein Cookie unter dem Namen PHPSESSID an den Browser gesendet haben. Wenn der Cookie-Name immer derselbe ist, gibt es natürlich keine Möglichkeit, zwei Sitzungen mit demselben Namen innerhalb desselben Browsers zu organisieren. Wenn wir jedoch für jeden Benutzer einen eigenen Sitzungsnamen verwenden würden, wäre das Problem gelöst. Lass es uns tun.

Funktion startSession($isUserActivity=true, $prefix=null) ( ... if (session_id()) return true; // Wenn das Benutzerpräfix in den Parametern übergeben wird, // einen eindeutigen Sitzungsnamen festlegen, der dies enthält Präfix, // andernfalls allgemeinen Namen für alle Benutzer festlegen (z. B. MYPROJECT) session_name("MYPROJECT".($prefix ? "_".$prefix: "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) return false; ... )

Jetzt müssen Sie nur noch sicherstellen, dass das aufrufende Skript für jeden Benutzer ein eindeutiges Präfix an die Funktion startSession() übergibt. Dies kann beispielsweise durch die Übergabe eines Präfixes in den GET/POST-Parametern jeder Anfrage oder durch ein zusätzliches Cookie erfolgen.

Fazit Abschließend werde ich den vollständigen endgültigen Code unserer Funktionen für die Arbeit mit PHP-Sitzungen bereitstellen, einschließlich aller oben besprochenen Aufgaben.

Funktion startSession($isUserActivity=true, $prefix=null) ( $sessionLifetime = 300; $idLifetime = 60; if (session_id()) return true; session_name("MYPROJECT".($prefix ? "_".$prefix: "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) return false; $t = time(); if ($sessionLifetime) ( if (isset($_SESSION["lastactivity"] ) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( destroySession(); return false; ) else ( if ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) if ($idLifetime ) ( if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $idLifetime) ( session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( $_SESSION["starttime"] = $t; ) ) return true; ) function destroySession() ( if (session_id()) ( session_unset(); setcookie(session_name(), session_id(), time() -60*60*24); session_destroy(); ) )

Ich hoffe, dass dieser Artikel denjenigen etwas Zeit spart, die sich noch nie zu tief mit dem Sitzungsmechanismus befasst haben, und denjenigen, die gerade erst anfangen, sich mit PHP vertraut zu machen, genügend Einblick in diesen Mechanismus gibt.

Benötigen Sie einen Benutzernamen und ein Passwort?

Um Artikel online einzureichen und den Status der eingereichten Artikel zu überprüfen, müssen Sie sich registrieren und bei Ihrem Konto anmelden.

Checkliste für die Vorbereitung eines Artikels zur Einreichung

Im Rahmen des Artikeleinreichungsprozesses müssen Autoren prüfen, ob ihr Artikel alle folgenden Punkte erfüllt; Artikel können an die Autoren zurückgegeben werden, wenn sie diese Anforderungen nicht erfüllen.

Der Artikel wurde entsprechend den Anforderungen erstellt

Bedingungen für die Übertragung des Urheberrechts

Die Autoren behalten das Urheberrecht an dem Werk und gewähren der Zeitschrift das Erstveröffentlichungsrecht zusammen mit dem Werk, während sie es unter den Bedingungen der Creative Commons Attribution License lizenzieren, die es anderen ermöglicht, dieses Werk mit obligatorischer Nennung des Autors des Werks und einem Link zu verbreiten zur Originalveröffentlichung in dieser Zeitschrift.

Datenschutzerklärung

Auf der Website dieses Magazins eingegebene Namen und E-Mail-Adressen werden ausschließlich für die in diesem Magazin genannten Zwecke verwendet und nicht für andere Zwecke verwendet oder an andere natürliche oder juristische Personen weitergegeben.

Vor der Registrierung im System stimmt der Nutzer den Richtlinien zur Verarbeitung und Speicherung personenbezogener Daten zu.

Autorenzahlungen

1500 Zeichen mit Leerzeichen: 300,00 (RUB)

Veröffentlichung einer Manuskriptseite (1500 Zeichen) – 300 Rubel. Grafikmaterialien / Tabellen werden separat bezahlt - 50 Rubel / 1 Stück. Das Autorenexemplar inklusive Versand innerhalb Russlands wird auf Wunsch des Autors bezahlt - 400 Rubel. Versand ins Ausland - 800 Rubel. Die Kosten für die Zusendung einer Bescheinigung über die Annahme des Materials zur Veröffentlichung betragen 150 Rubel.

Übersetzung der Begleitinformationen (vollständiger Name, Arbeitsort der Autoren; Titel; Zusammenfassung; Schlüsselwörter) ins Englische 0,5 Rubel für jedes Zeichen, einschließlich Leerzeichen.

Aufmerksamkeit! Autoren (Kandidaten und Doktoren der Wissenschaften), die laut elibrary.ru 300 oder mehr Zitate haben (der Anteil der Selbstzitate sollte nicht mehr als 30 % betragen), werden kostenlos veröffentlicht. Wenn Sie Anspruch auf eine kostenlose Veröffentlichung haben, geben Sie beim Einreichen von Material im Kommentarfeld einen Link zu Ihrem Bibliotheksprofil mit der Anzahl der Zitate an. Die Versandkosten für die Abholung werden gesondert vergütet.

Die Website-Sicherheit basiert auf der Sitzungsverwaltung. Wenn ein Benutzer eine Verbindung zu einer sicheren Site herstellt, gibt er Anmeldeinformationen an, normalerweise in Form eines Benutzernamens und eines Kennworts. Der Webserver hat keine Ahnung, welcher Benutzer bereits angemeldet ist oder wie er von Seite zu Seite navigiert. Der Sitzungsmechanismus verhindert, dass Benutzer jedes Mal ein Passwort eingeben müssen, wenn sie eine neue Aktion ausführen oder eine neue Seite aufrufen möchten.

Im Wesentlichen stellt die Sitzungsverwaltung sicher, dass der aktuell verbundene Benutzer derjenige ist, der authentifiziert wurde. Doch leider sind Sitzungen zu einem offensichtlichen Ziel für Hacker geworden, da sie den Zugriff auf einen Webserver ermöglichen können, ohne dass eine Authentifizierung erforderlich ist.

Nach der Authentifizierung des Benutzers stellt ihm der Webserver eine Sitzungs-ID zur Verfügung. Diese ID wird im Browser gespeichert und bei jeder Authentifizierung ersetzt. Dadurch können Sie wiederholte Anmelde-/Passworteingabevorgänge vermeiden. All dies geschieht im Hintergrund und bereitet dem Benutzer keine Unannehmlichkeiten. Stellen Sie sich vor, Sie würden Ihren Benutzernamen und Ihr Passwort jedes Mal eingeben, wenn Sie eine neue Seite aufrufen!

In diesem Artikel werde ich versuchen, alle mir bekannten Möglichkeiten zum Schutz der Sitzungs-ID in PHP zu beschreiben.

Verwendung von Cookies Standardmäßig werden alle Sitzungsinformationen, einschließlich der ID, an ein Cookie gesendet. Aber das passiert nicht immer. Einige Benutzer deaktivieren Cookies in ihren Browsern. In diesem Fall übergibt der Browser die Sitzungs-ID in der URL.

Hier wird die ID im Klartext übertragen, im Gegensatz zu einer Sitzung über ein Cookie, bei dem die Informationen im HTTP-Header verborgen sind. Der einfachste Weg, sich dagegen zu schützen, besteht darin, die Übertragung der Sitzungskennung über die Adressleiste zu verbieten. Dies kann erreicht werden, indem Sie Folgendes in die .htaccess-Konfigurationsdatei des Apache-Servers schreiben:

PHP_flag session.use_only_cookies aktiviert

Verwenden der Verschlüsselung Wenn Ihre Website vertrauliche Informationen wie Kreditkartennummern (Hallo von Sony) verarbeiten muss, sollten Sie SSL3.0- oder TSL1.0-Verschlüsselung verwenden. Dazu müssen Sie beim Setzen eines Cookies für den sicheren Parameter true angeben.

Wenn Sie das Sitzungspasswort in der Variablen $_SESSION speichern (es ist immer noch besser, SQL zu verwenden), sollten Sie es nicht im Klartext speichern.

If ($_SESSION["password"] == $userpass) ( // code )

Der obige Code ist nicht sicher, da das Passwort als Klartext in einer Sitzungsvariablen gespeichert wird. Verwenden Sie stattdessen die MD5-Verschlüsselung, etwa so:

If ($_SESSION["md5password"] == md5($userpass)) ( // Code )

Browserprüfung Um die Möglichkeit der Nutzung einer Sitzung von einem anderen Browser (Computer) aus zu verhindern, sollten Sie eine Prüfung des HTTP-Headerfelds User-Agent eingeben:

Session_start(); if (isset($_SESSION["HTTP_USER_AGENT"])) ( if ($_SESSION["HTTP_USER_AGENT"] != md5($_SERVER["HTTP_USER_AGENT"])) ( // Code ) ) else ( $_SESSION["HTTP_USER_AGENT" ] = md5($_SERVER["HTTP_USER_AGENT"]); )

Sitzungsablauf Begrenzen Sie die Lebensdauer der Sitzung sowie die Ablaufzeit von Cookies. Standardmäßig beträgt die Sitzungsdauer 1440 Sekunden. Sie können diesen Wert über php.ini und .htaccess ändern. Beispiel für .htaccess:

# Sitzungsdauer in Sekunden
php_value session.gc_maxlifetime 3600
# Cookie-Lebensdauer in Sekunden
php_value session.cookie_lifetime 3600

Bindung nach IP-Adresse In bestimmten Situationen (nicht immer) sollten Sie eine Bindung nach IP-Adresse durchführen. Vor allem, wenn die Anzahl der Benutzer begrenzt ist und statische IPs haben. Die Prüfung kann entweder anhand der Liste der erlaubten IP-Adressen erfolgen,

Include("ip_list.php"); //$ip_white_list = array ("admin1" => "111.222.333.444", "admin2" => "555.666.777.888"); if(!empty(array_search($_SERVER["REMOTE_ADDR"],$ip_white_list))) ( header("Location: admin.php"); ) else ( echo "ACCESS DENY!"; )

Oder nach IP-Adresse für jede Anfrage (nur für statische IP):

If(isset($_SESSION["ip"]) and $_SESSION["ip"] == $_SERVER["REMOTE_ADDR"]) ( header("Location: admin.php"); ) else ( session_unset(); $ _SESSION["ip"] = $_SERVER["REMOTE_ADDR"]; )

Sie sollten sich darüber im Klaren sein, dass Hacking nicht vollständig vermieden werden kann. Sie können diesen Hack nur mit allen bekannten Mitteln so schwierig wie möglich machen. Sie sollten jedoch auch Ihre legalen Benutzer nicht vergessen, um ihnen das Leben durch einen solchen Schutz nicht zu erschweren.

Dieser Artikel wurde 2009 verfasst und ist nach wie vor einer unserer beliebtesten Beiträge. Wenn Sie mehr über PHP und MySQL erfahren möchten, ist dies möglicherweise von großem Interesse.

HINWEIS: Dieser Artikel wurde neu aktualisiert, um auf PHP 4.2 oder höher zu funktionieren!

Kürzlich hatte ich die Gelegenheit, mit einer Gruppe von Menschen an einem kleinen Projekt zu arbeiten. Schon früh war uns klar, dass E-Mail allein nicht ausreichen würde, um alle auf dem Laufenden zu halten, und so wurde ich damit beauftragt, eine kleine Website für das Projekt zu erstellen. Es würde ein einfaches Message Board enthalten, einen Ort, an dem wir Dokumente und andere Dateien zur Nutzung durch den Rest des Teams hochladen könnten, sowie Kontaktinformationen für die verschiedenen Teammitglieder.

Damit viele dieser Funktionen funktionieren, war mir klar, dass sich Benutzer anmelden müssen, bevor sie auf die relevanten Teile der Website zugreifen können. Was ich brauchte, war ein System, das es Benutzern ermöglicht, sich für den Zugriff auf die Website mit einer Benutzer-ID zu registrieren und diese ID dann sofort zu verwenden, ohne dass ich eingreifen muss.

In diesem Artikel werde ich einen Überblick über das von mir entwickelte System geben, beginnend in der ersten Hälfte mit dem Benutzerregistrierungsprozess. In der zweiten Hälfte konzentriere ich mich auf die Website selbst und darauf, wie Benutzer sich anmelden müssen und diesen Anmeldestatus dann während ihres gesamten Besuchs beibehalten. Besonderes Augenmerk werde ich auf die Verwendung der Sitzungsverwaltungsfunktionen in PHP legen. Am Ende sollten Sie über alle Informationen verfügen, die Sie benötigen, um ein ähnliches eigenes System zu implementieren.

In diesem Artikel gehe ich davon aus, dass Sie über grundlegende Kenntnisse der PHP-Sprache, der Verwendung von Formularen zur Übermittlung von Informationen an ein PHP-Skript und der Verwendung von PHP zur Interaktion mit einer MySQL-Datenbank verfügen. Wenn Ihnen eines dieser Konzepte fremd ist, sollten Sie zunächst meinen vorherigen Artikel lesen.

Teil eins: Der Anmeldevorgang Das Anmeldeformular

Ein natürlicher Ausgangspunkt für den Aufbau einer Website, für deren Zugriff sich Benutzer registrieren müssen, ist der Registrierungsprozess selbst. Wie zu erwarten ist, reicht ein einfaches webbasiertes Formular aus. So wird es aussehen:

Und hier ist der Code für dieses Formular:




Neue Benutzerregistrierung



Registrierungsformular für neue Benutzer

* Markiert eine notwendiges Feld


Nachdem das Ziel nun klar ist, werde ich Sie durch den Code für accesscontrol.php führen. Beginnen Sie damit, Ihre beiden praktischen Include-Dateien einzubinden: