Cookies, Sitzungen und Persistenz

Einführung

HTTP (HyperText Transfer Protocol) wurde entwickelt, um ein zustandsloses Anforderungs-Antwort-Modell für die Datenübertragung von einem Server zu einem Client zu unterstützen. Die erste Version 1.0 unterstützte ein reines 1:1-Verhältnis zwischen Anfragen und Verbindungen (d. h. pro Verbindung wurde ein Paar aus Anfragen und Antworten unterstützt).

In Version 1.1 wurde dieses Verhältnis auf N:1 erweitert, also auf viele Anfragen pro Verbindung. Ziel dieser Maßnahme war es, der zunehmenden Komplexität von Webseiten Rechnung zu tragen, einschließlich der vielen Objekte und Elemente, die vom Server zum Client übertragen werden müssen.

Mit der Einführung von 2.0 unterstützt HTTP weiterhin ein Modell mit vielen Anfragen pro Verbindung. Die radikalsten Änderungen betreffen den Austausch von Headern und den Wechsel von der textbasierten zur binären Übertragung.

Irgendwann wurde HTTP mehr als nur ein einfacher Mechanismus zum Übertragen von Text und Bildern von einem Server zu einem Client; es wurde zu einer Plattform für Anwendungen. Die Allgegenwärtigkeit des Browsers, seine plattformübergreifende Natur und die einfache Bereitstellung von Anwendungen ohne die hohen Kosten für die Unterstützung mehrerer Betriebssysteme und Umgebungen waren sicherlich ansprechend. Leider wurde HTTP nicht als Anwendungstransportprotokoll konzipiert. Es wurde für die Übertragung von Dokumenten entwickelt. Selbst moderne Verwendungen von HTTP, beispielsweise von APIs, gehen von einer dokumentähnlichen Nutzlast aus. Ein gutes Beispiel hierfür ist JSON, ein als Text übertragenes Schlüssel-Wert-Paar-Datenformat. Obwohl Dokumente und Anwendungsprotokolle im Allgemeinen textbasiert sind, enden hier die Ähnlichkeiten.

Herkömmliche Anwendungen erfordern eine Möglichkeit zur Beibehaltung ihres Status, während dies bei Dokumenten nicht der Fall ist. Anwendungen basieren auf logischen Abläufen und Prozessen. Für beides muss die Anwendung wissen, wo sich der Benutzer gerade befindet, und dafür ist ein Status erforderlich. Trotz der inhärent zustandslosen Natur von HTTP ist es zum De-facto-Anwendungstransportprotokoll des Webs geworden. In einem der am weitesten verbreiteten und nützlichsten Hacks der Technikgeschichte wurde HTTP mit der Möglichkeit ausgestattet, den Status während der Verwendung einer Anwendung zu verfolgen. Bei diesem „Hack“ kommen Sitzungen und Cookies ins Spiel.

Sitzungen
Das Zustandslose in das Zustandsbehaftete verwandeln

Sitzungen sind die Art und Weise, wie Web- und Anwendungsserver ihren Status aufrechterhalten. Diese einfachen Speicherblöcke sind mit jeder TCP-Verbindung zu einem Web- oder Anwendungsserver verknüpft und dienen als In-Memory-Speicher für Informationen in HTTP-basierten Anwendungen.

Wenn ein Benutzer zum ersten Mal eine Verbindung zu einem Server herstellt, wird eine Sitzung erstellt und mit dieser Verbindung verknüpft. Entwickler verwenden diese Sitzung dann als Ort zum Speichern anwendungsrelevanter Daten. Diese Daten können von wichtigen Informationen wie einer Kunden-ID bis hin zu weniger wichtigen Daten reichen, beispielsweise wie Sie die Startseite der Site angezeigt bekommen möchten.

Das beste Beispiel für die Nützlichkeit einer Sitzung sind Einkaufswagen, da fast jeder von uns schon einmal online eingekauft hat. Artikel in einem Einkaufswagen bleiben im Laufe einer „Sitzung“ erhalten, da jeder Artikel in Ihrem Einkaufswagen in irgendeiner Weise in der Sitzung auf dem Server dargestellt wird. Ein weiteres gutes Beispiel sind Anwendungen zur Produktkonfiguration oder -anpassung im Assistentenstil. Mit diesen „Mini“-Anwendungen können Sie eine Reihe von Optionen durchsuchen und auswählen. Am Ende sind Sie normalerweise schockiert über die geschätzten Kosten für all den Schnickschnack, den Sie hinzugefügt haben. Während Sie durch die einzelnen „Optionsbildschirme“ klicken, werden die anderen von Ihnen ausgewählten Optionen in der Sitzung gespeichert, sodass sie einfach abgerufen, hinzugefügt oder gelöscht werden können.

Moderne Anwendungen sind so konzipiert, dass sie zustandslos sind, ihre Architekturen entsprechen diesem Prinzip jedoch möglicherweise nicht. Moderne Skalierungsmethoden basieren häufig auf Architekturmustern wie Sharding, bei dem Routing-Anfragen auf der Grundlage einiger indizierbarer Daten wie Benutzername oder Kontonummer erforderlich sind. Dies erfordert eine Art zustandsbehafteten Ansatz, bei dem die indizierbaren Daten bei jeder Anforderung mitgeführt werden, um ein ordnungsgemäßes Routing und Anwendungsverhalten sicherzustellen. In dieser Hinsicht erfordern moderne „zustandslose“ Anwendungen und APIs oft eine ähnliche Pflege und Wartung wie ihre zustandsbehafteten Vorgänger.

Das Problem besteht darin, dass Sitzungen an Verbindungen gebunden sind und Verbindungen, die zu lange inaktiv bleiben, ablaufen. Außerdem ist die Definition von „zu lang“ bei Verbindungen ganz anders als bei Sitzungen. Die Standardkonfiguration einiger Webserver besteht beispielsweise darin, eine Verbindung zu schließen, wenn sie inaktiv war, d. h. wenn 15 Sekunden lang keine weiteren Anfragen gestellt wurden. Umgekehrt bleibt eine Sitzung auf diesen Webservern standardmäßig 300 Sekunden oder 5 Minuten im Speicher. Offensichtlich stehen diese beiden Dinge im Widerspruch zueinander, denn was nützt die Sitzung, wenn die Verbindung einmal abgelaufen ist und sie mit der Verbindung verknüpft ist?

Sie denken vielleicht, Sie könnten diese Diskrepanz beheben, indem Sie einfach den Timeout-Wert für die Verbindung entsprechend der Sitzung erhöhen. Eine Erhöhung des Zeitlimits bedeutet, dass Sie möglicherweise Speicher aufwenden, um eine Verbindung aufrechtzuerhalten, die möglicherweise nicht verwendet wird. Dies kann die Gesamtkapazität gleichzeitiger Benutzer Ihres Servers verringern und letztendlich seine Leistung beeinträchtigen. Und Sie möchten das Sitzungstimeout sicher nicht so verkürzen, dass es dem Verbindungtimeout entspricht, da die meisten Leute mehr als fünf Minuten damit verbringen, sich umzusehen oder ihr neues Spielzeug anzupassen.

 

Wichtiger Hinweis: Während HTTP/2 einige dieser Probleme behebt, führt es andere ein, die mit der Statusbeibehaltung zusammenhängen. Obwohl es in der Spezifikation nicht erforderlich ist, erlauben die gängigen Browser nur HTTP/2 über TLS/SSL. Beide Protokolle erfordern Beständigkeit, um die Leistungseinbußen durch Neuverhandlungen zu vermeiden, was wiederum Sitzungsbewusstsein, auch als zustandsbehaftetes Verhalten bezeichnet, erfordert.

 

Das Ergebnis sind Sitzungen, die als Speicher auf dem Server verbleiben, selbst wenn die zugehörigen Verbindungen aufgrund von Inaktivität beendet wurden. Dies verbrauchen wertvolle Ressourcen und verärgern möglicherweise Benutzer, für die Ihre Anwendung einfach nicht funktioniert.

Glücklicherweise wird dieses Problem durch die Verwendung von Cookies gelöst.

Kekse
Die Spur der Krümel führt nach Hause

Cookies sind Datenstücke, die vom Browser auf dem Client gespeichert werden. Cookies können alle möglichen interessanten Informationen über Sie, Ihre Anwendungen und die von Ihnen besuchten Websites speichern und tun dies auch. Der Begriff „Cookie“ leitet sich von „Magic Cookie“ ab, einem bekannten Konzept in der UNIX-Computertechnik, das sowohl die Idee als auch den Namen inspirierte. Cookies werden über den HTTP-Header „Cookie“ erstellt und zwischen Browser und Server ausgetauscht.

 

  Kekse: JSESSIONID=9597856473431 Cache-Steuerung: kein Cache Host: 127.0.0.2:8080 Verbindung: Am Leben bleiben
 

Der Browser weiß automatisch, dass er das Cookie im HTTP-Header in einer Datei auf Ihrem Computer speichern soll, und verfolgt Cookies auf Domänenbasis. Die Cookies für eine bestimmte Domäne werden vom Browser immer in den HTTP-Headern an den Server übergeben, sodass Entwickler von Webanwendungen diese Werte abrufen können, indem sie sie einfach auf der Serverseite der Anwendung anfordern.

Das Problem der Sitzungs-/Verbindungsdauer wird durch ein Cookie gelöst. Fast alle modernen Webanwendungen generieren eine „Session-ID“ und geben diese als Cookie weiter. Dadurch kann die Anwendung die Sitzung auf dem Server finden, selbst wenn die Verbindung, aus der die Sitzung erstellt wurde, geschlossen wird. Durch diesen Austausch von Sitzungs-IDs bleibt der Status auch bei einem zustandslosen Protokoll wie HTTP erhalten. Doch was passiert, wenn der Einsatz einer Webanwendung die Kapazität eines einzelnen Web- oder Anwendungsservers übersteigt? Normalerweise wird ein Load Balancer oder in heutigen Architekturen ein Application Delivery Controller (ADC) eingeführt, um die Anwendung so zu skalieren, dass alle Benutzer mit der Verfügbarkeit und Leistung zufrieden sind.

In modernen Anwendungen werden möglicherweise noch Cookies verwendet, andere HTTP-Header werden jedoch kritisch. API-Schlüssel zur Authentifizierung und Autorisierung werden häufig über einen HTTP-Header sowie andere benutzerdefinierte Header transportiert, die die für das Routing und die ordnungsgemäße Skalierung der Backend-Dienste erforderlichen Daten enthalten. Dabei ist es weniger wichtig, ob zum Übertragen dieser Daten das herkömmliche „Cookie“ oder ein anderer HTTP-Header verwendet wird, als die Bedeutung dieser Daten für die Gesamtarchitektur anzuerkennen.

Das Problem dabei ist, dass sich Lastausgleichsalgorithmen im Allgemeinen nur mit der Verteilung von Anforderungen auf Server befassen. Lastausgleichstechniken basieren auf Industriestandardalgorithmen wie Round Robin, Least Connections oder Fastest Response Time. Keiner von ihnen ist zustandsbehaftet und es ist möglich, dass derselbe Benutzer jede an eine Anwendung gerichtete Anfrage an einen anderen Server verteilt. Dadurch wird die gesamte Arbeit zur Implementierung des Status für HTTP nutzlos, da die in der Sitzung eines Servers gespeicherten Daten selten mit anderen Servern im „Pool“ geteilt werden.

Hier ist das Konzept der Persistenz hilfreich.

Beständigkeit
Das Band, das verbindet

Persistenz – auch als Stickiness bekannt – ist eine von ADCs implementierte Technik, um sicherzustellen, dass Anfragen eines einzelnen Benutzers immer an den Server verteilt werden, auf dem sie gestartet wurden. Einige Produkte und Dienste zum Lastenausgleich beschreiben diese Technik als „Sticky Sessions“, was eine völlig passende Bezeichnung ist.

Persistenz wird schon seit langem zum Lastenausgleich von SSL/TLS-fähigen Sites verwendet, da ein erneuter Start des Prozesses die Leistung erheblich beeinträchtigen würde, wenn der rechenintensive Verhandlungsprozess erst einmal abgeschlossen und die Schlüssel ausgetauscht sind. Daher implementierten ADCs die SSL-Sitzungspersistenz, um sicherzustellen, dass Benutzer immer zu demselben Server weitergeleitet wurden, mit dem sie sich zuerst verbunden hatten.

Im Laufe der Jahre machten Browserimplementierungen die Entwicklung einer Technik erforderlich, um die kostspielige Neuverhandlung dieser Sitzungen zu vermeiden. Diese Technik wird als cookiebasierte Persistenz bezeichnet.

Anstatt sich auf die SSL/TLS-Sitzungs-ID zu verlassen, fügt der Load Balancer beim ersten Zugriff eines Clients auf die Site ein Cookie ein, um die Sitzung eindeutig zu identifizieren, und verweist dann bei nachfolgenden Anforderungen auf dieses Cookie, um die Verbindung mit dem entsprechenden Server aufrechtzuerhalten.

Das Konzept der Cookie-basierten Persistenz wird seitdem auch auf Anwendungssitzungen angewendet. Dabei werden von Web- und Anwendungsservern generierte Sitzungs-ID-Informationen verwendet, um sicherzustellen, dass Benutzeranforderungen während derselben Sitzung immer an denselben Server weitergeleitet werden. Ohne diese Funktion müssten Anwendungen, die einen Lastenausgleich erfordern, eine andere Möglichkeit finden, Sitzungsinformationen auszutauschen, oder auf längere Sitzungs- und Verbindungstimeouts zurückgreifen, bis die Zahl der Server, die zur Unterstützung der Benutzerbasis erforderlich sind, schnell zu einer unüberschaubaren Größe anwachsen würde.

Obwohl die gebräuchlichste Form der Persistenz mithilfe von Sitzungs-IDs implementiert wird, die im HTTP-Header übergeben werden, können ADCs heutzutage auch andere Datenelemente persistent speichern. Alle Daten, die in einem Cookie gespeichert oder aus den IP-, TCP- oder HTTP-Headern abgeleitet werden können, können zum Aufrechterhalten einer Sitzung verwendet werden. Tatsächlich können alle Daten in einer Anwendungsnachricht, die den Benutzer eindeutig identifizieren, von einem intelligenten ADC verwendet werden, um eine Verbindung zwischen dem Browser und einem Server aufrechtzuerhalten.

Abschluss

HTTP mag zwar ein zustandsloses Protokoll sein, aber es ist uns gelungen, den Zustand in das allgegenwärtige Protokoll hineinzuzwängen. Durch die Verwendung von Persistenz- und Application Delivery Controllern ist es möglich, hochverfügbare, leistungsfähige Webanwendungen zu entwickeln, ohne die etwas instabile Integration von Cookies und Sitzungen zu beeinträchtigen, die zur Aufrechterhaltung des Status erforderlich ist.

Diese Funktionen verleihen HTTP einen Status, obwohl seine Implementierung und Ausführung zustandslos bleiben. Ohne Cookies, Sitzungen und Persistenz hätten wir sicherlich ein zustandsbehaftetes Protokoll gefunden, auf dem wir unsere Anwendungen aufbauen könnten. Stattdessen vermitteln die Features und Funktionen von Application Delivery Controllern zwischen Browsern (Clients) und Servern, um diese Funktionalität bereitzustellen. Dadurch wird der Nutzen von HTTP über statische Webseiten und herkömmliche Anwendungen hinaus auf moderne, auf Mikrodiensten basierende Architekturen und den Liebling der digitalen Wirtschaft, die API, ausgeweitet.

Veröffentlicht am 19. Januar 2018
  • Auf Facebook teilen
  • Teilen mit X
  • Auf Linkedin teilen
  • Teilen per E-Mail
  • Teilen über AddThis

Verbinden mit F5

F5 Labs

Die neuesten Erkenntnisse im Bereich Anwendungsbedrohungsinformationen.

DevCentral

Die F5-Community für Diskussionsforen und Expertenartikel.

F5-Newsroom

Neuigkeiten, F5-Blogs und mehr.