Falscher Ablaufzeitpunkt von Cookies
Stefan Bion
- webserver
Hi zusammen,
ich habe auf meinem Webspace schon seit Jahren diverse selbstgezimmerte Perl-CGIs laufen, wie Gästebuch, TV-Tips und Online-Vereinsverwaltung. Die CGIs haben keine Session-Verwaltung, sondern speichern Username und Paßwort in verschlüsselter Form in Cookies mit einem Ablaufzeitpunkt von 1 Stunde ab der aktuellen Zeit. Auf diese Weise kann das Script erkennen, daß der Benutzer noch eingeloggt ist und ihn nach 1 Stunde Inaktivität automatisch ausloggen. Funktionierte bis jetzt auch alles wunderbar.
Seit heute abend habe ich jedoch ein Problem in Opera 9.02/Windows: Der Ablaufzeitpunkt gesetzter Cookies liegt 1 Stunde in der Vergangenheit, statt 1 Stunde in der Zukunft. Also eine Differenz von -2 Stunden.
Wenn man auf die Shell des Servers geht und dort die aktuelle Zeit abfragt (date
), wird dort auch tatsächlich "Fre Mär 9 22:57:01 CET 2007" ausgegeben, obwohl es in Wirklichkeit eigentlich knapp 2 Stunden später ist, nämlich der 10.03.2007 um 00:54 Uhr. Wenn ich dann testweise mal die Cookie-Ablaufzeit auf 2 Stunden erweitere, bleiben die gesetzten Cookies auch tatsächlich für 3 Minuten gültig (2 Stunden minus der Zeitdiffrenz zwischen Client und Server von 1:57 Stunden).
(Die Cookie-Ablaufzeit errechne ich im Script übrigens mittels gmtime(time + 3600)
, und auch die dabei ermittelte GMT-Zeit ist gegenüber der tatsächlichen GMT-Zeit natürlich um 2 Stunden zu früh.)
Ein Blick auf die Support-Seite des Providers offenbart übrigens, daß heute "im Lauf des Tages verschiedene Wartungsarbeiten" durchgeführt wurden - ich nehme also mal an, daß dabei die Serverzeit verstellt wurde...
S e l t s a m e r w e i s e tritt dieses Problem jedoch nicht beim Firefox auf! Dort haben die Cookies korrekte Ablaufzeitpunkte, nämlich genau die 1 Stunde (minus 3 Minuten) in der Zukunft. Anscheinend korrigiert Firefox die (falsche) Server-Zeit automatisch so, daß sie mit der Client-Zeit übereinstimmt. W i e m a c h t d e r d a s ? Und gibt es eine Möglichkeit, dies auch bei Opera zu erreichen?
Oder gibt es eine andere Möglichkeit, CGI-seitig zu erreichen, daß sich die Ablaufzeit von Cookies an der Client-Zeit orientiert? Klar, man könnte per JavaScript in einer Hidden-Variable des Formulars die aktuelle Client-Uhrzeit an den Server übermitteln und diese als Referenz benutzen, aber das ist sicherlich nicht der "Königsweg"...
Gruß,
Stefan
Moin,
Oder gibt es eine andere Möglichkeit, CGI-seitig zu erreichen, daß sich die Ablaufzeit von Cookies an der Client-Zeit orientiert? Klar, man könnte per JavaScript in einer Hidden-Variable des Formulars die aktuelle Client-Uhrzeit an den Server übermitteln und diese als Referenz benutzen, aber das ist sicherlich nicht der "Königsweg"...
Vermutlich aber der einzigste Weg.
roro
Hi Rolf,
Vermutlich aber der einzigste Weg.
Gefällt mir aber nicht... ist zu abhängig von Client-Features.
Und der Firefox wird es vermutlich so machen, daß er einfach die im HTTP-Response-Header übermittelte Serverzeit von der Clientzeit subtrahiert und diese Differenz nochmal von der Cookie-Ablaufzeit subtrahiert, damit sich die Lebensdauer an der Client-Zeit orientiert und nicht an der (u.U falschen) Serverzeit.
Übrigens, wäre nicht der Parameter "Max-age" besser geeignet? Den habe ich bisher gar nicht gekannt, aber wenn man dem Browser damit einfach nur die Lebensdauer des Cookies in Sekunden mitteilen könnte, und der sich an der Client-Zeit orientiert, wäre das Problem doch gelöst, oder? Habe ich allerdings noch nicht ausgetestet...
Gruß,
Stefan
Moin!
Oder gibt es eine andere Möglichkeit, CGI-seitig zu erreichen, daß sich die Ablaufzeit von Cookies an der Client-Zeit orientiert? Klar, man könnte per JavaScript in einer Hidden-Variable des Formulars die aktuelle Client-Uhrzeit an den Server übermitteln und diese als Referenz benutzen, aber das ist sicherlich nicht der "Königsweg"...
Als allererstes sollte dich interessieren, was dein Code eigentlich für Cookies im HTTP-Header produziert. Denn nur das hat Einfluß auf den Browser.
Und diese Angabe wäre dann abzugleichen mit der für eine korrekte Gültigkeitsdauer.
Bei deiner date-Ausgabe beispielsweise springt sofort der Umlaut im "Mär" ins Auge. Der gehört da nur hin, wenn du deutsche Konsolenausgabe hast, aber er gehört garantiert nicht in eine Cookieangabe, da wäre "Mar" korrekt (englische Form).
Kann ja durchaus sein, dass dir das letzten Monat (de:Feb == en:Feb) oder den Monat davor (de:Jan == en:Jan) nicht aufgefallen ist.
Und dass Opera bei deutschen Monatskürzeln irgendeine komische Fehlerkorrektur macht.
- Sven Rautenberg
Hi Sven,
Als allererstes sollte dich interessieren, was dein Code
eigentlich für Cookies im HTTP-Header produziert. Denn nur das hat
Einfluß auf den Browser.
Schon klar. Der produziert einen standardkonformen Zeitstempel-String, z.B.:
Sat, 10-Mar-2007 12:53:29 GMT
Die entsprechende Konsolen-Ausgabe sieht so aus:
Sam Mär 10 13:57:54 CET 2007
Die kann aber aussehen, wie sie will, da sie mit dem Code zum Ermitteln der Cookie-Ablaufzeit nichts zu tun hat:
---------------------------------------------------------------------
my $LoginAblaufdatum = MakeCookieExpireDatum(3600); # Das Login soll nach 1 Stunde Inaktivität ablaufen.
SetCookie('VvUsername', $username, $LoginAblaufdatum);
sub MakeCookieExpireDatum
{
my $Sekunden = shift;
my @Wochentage = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
my @Monate = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
my ($Sekunde, $Minute, $Stunde, $Tag, $Monat, $Jahr, $Wochentag) = gmtime(time + $Sekunden);
my $ExpireDate = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT", $Wochentage[$Wochentag], $Tag, $Monate[$Monat], $Jahr + 1900, $Stunde, $Minute, $Sekunde);
$ExpireDate;
}
sub SetCookie
{
my $CookieName = shift;
my $CookieValue = shift;
my $CookieExpireDate = shift;
$CookieValue =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
$CookieExpireDate = 'Fri, 01-Jan-2038 00:00:00 GMT' if('' eq $CookieExpireDate);
print "Set-Cookie: $CookieName=$CookieValue; Expires=$CookieExpireDate\n";
}
---------------------------------------------------------------------
Kann ja durchaus sein, dass dir das letzten Monat (de:Feb == en:Feb) oder den Monat davor (de:Jan == en:Jan) nicht aufgefallen ist.
Die Scripts laufen schon mehrere Jahre.
Gruß,
Stefan
Hallo Stefan,
S e l t s a m e r w e i s e tritt dieses Problem jedoch nicht beim Firefox auf! Dort haben die Cookies korrekte Ablaufzeitpunkte, nämlich genau die 1 Stunde (minus 3 Minuten) in der Zukunft. Anscheinend korrigiert Firefox die (falsche) Server-Zeit automatisch so, daß sie mit der Client-Zeit übereinstimmt. W i e m a c h t d e r d a s ?
Bei HTTP gibt's ein Header-Feld namens 'Date', das die Serverzeit angibt, d.h. der Browser kennt die Serverzeit. Dann berechnet Firefox offensichtlich die Differenz zwischen Cookie-Expire-Datum und dem aktuellen Serverdatum und addiert das auf die *lokale* Client-Zeit drauf.
Und gibt es eine Möglichkeit, dies auch bei Opera zu erreichen?
Wenn Opera das defaultmäßig nicht macht: ich bezweifle, dass es dafür eine Einstellung gibt.
Und ganz ehrlich: In meinen Augen ist das ganze ein grundsätzliches Problem: Welche Zeit ist gemeint? Das geht ja nicht nur bei Cookies so, sondern auch bei Caching-Dingen wie Expires / Cache-Control: max-age etc. Das Problem ist doch schlichtweg, dass ja unterschiedliche Semantiken hinter den Angaben stecken könnten:
* Du willst ein Cookie setzen, das exakt am 1. Januar 2015 ausläuft, weil da irgend ein tolles Ereignis stattfindet oder sowas. Dann soll die Datumsangabe nicht mehr umgerechnet werden, denn sonst trifft der Client das anvisierte Datum nicht mehr richtig.
* Du willst ein Cookie setzen, das *ab Abruf* x Sekunden gilt. Dann ist es vmtl. am sinnvollsten, die Datumsangabe bezüglich der Differenz zwischen Client- und Serverzeit zu korrigieren.
Es gibt aber keine Möglichkeit, beim Setzen eines Cookies zu sagen, welche der beiden Dinge gewünscht ist. Genausowenig bei Caching-Headern. Ich habe jetzt auch nicht nachgelesen, was der HTTP-Standard in diesem Fall vorschreibt, mich würde es aber nicht wundern, wenn er's offen lässt.
Die einzige _saubere_ Lösung ist in meinen Augen: Sorge dafür, dass die Serverzeit korrekt ist (d.h. mit dem Support sprechen), denn wenn sowohl Client als auch Server die gleiche Uhrzeit haben, dann tritt das Problem *nicht* auf.
Viele Grüße,
Christian