SUCHE MIT Google
Web virtualuniversity.ch
HOME DIDAKTIK ECDL ELEKTRONIK GUIDES HR MANAGEMENT MATHEMATIK SOFTWARE TELEKOM
DIENSTE
Anmeldung
Newsletter abonnieren
Sag's einem Freund!
VirtualUniversity als Startseite
Zu den Favoriten hinzufügen
Feedback Formular
e-Learning für Lehrer
Spenden
Autoren login
KURSE SUCHEN
Kurse veröffentlichen

Suche nach Datum:

Suche mit Schlüsselwort:

Suche nach Land:

Suche nach Kategorie:
PARTNER
ausbildung24.ch - Ausbildungsportal, Seminare, Kursen... 

 
HTMLopen.de - Alles was ein Webmaster braucht

 
PCopen.de - PC LAN Netze und Netzwerke - alles was ein IT Profi und Systemtechnicker braucht

TELEKOM

Fortgeschrittene CGI-Programmierung

Session-Tracking

Ein Problem bei CGI-Programmen ist, daß es sich bei HTTP um einzustandsloses Protokoll handelt. Bei jeder Interaktion wird ein CGI-Programmaufs Neue aufgerufen. Ohne besondere Maßnahmen ist nur eine Anfrage desBrowsers, gefolgt von einer Antwort des CGI-Programms, möglich. So lassen sich viele Anwendungen nicht realisieren. Stellen Sie sich ein Bestellsystem vor. Dieses erlaubt es, Waren in einen virtuellen Warenkorb zu stellen. Dieser Vorgang kann sich über mehrere Aufrufe des CCI-Programms erstrecken und wird entweder mit einem Abbruch der Aktion oder mit dem "Bezahlen" an der "Kasse" abgeschlossen. Ein solches System ist jedoch nicht durch einfache Frage/Antwort-Folgen zu realisieren.

Man muß also Methoden finden, mit denen der Zustand zwischen mehreren Aufrufen des CGI-Programms erhalten bleibt, und die ein zustandsloses (stateless) Protokoll nutzen um ein zustandsbehaftetes (stateful) Protokoll darüber implementieren.Ein CGI-Programm selbst kann zunächst keinen Zustand halten. Wir wollen aber die mehrfache Ausführung eines CGI-Programms als ein virtuelles Programm auffassen, das bei jedem CGI-Aufruf in einen neuen Zustand übergeht.

Ein einfaches Beispiel:
Bei jedem Aufruf des CGI-Programms soll eine Zahl (Session-Kennung) angezeigt werden. Diese Zahl ist bei jedem neuen Aufruf zu inkrementieren. Jeder Browser bzw. Benutzer soll eine eigene Kennung besitzen, so daß es nicht ausreicht, einen globalen Zähler serverseitig zu erhöhen.

Der Zähler repräsentiert den Session-Zustand. Diesen müssen wir jeweils zwischen zwei aufeinanderfolgenden Aufrufen des CCI-Programms erhalten. Da der Zustand pro Browser bzw. User gilt, muß dieser mehrfach gespeichert werden. Zur Speicherung des Zustands gibt es zwei Möglichkeiten:

  • Der komplette Zustand wird clientseitig gespeichert. Hierbei kann er in einer Browsersitzung versteckt sein oder aber auch in Form von Cookies auf der Festplatte des Browsers liegen.
  • Der Zustand aller Clients wird serverseitig gespeichert. Es ist dabei notwendig, bei den Clients noch eine minimale Zustandsinformation zu hinterlegen. Diese Informationsmenge wird auch Sitzungsschlüssel genannt.
Die clientseitige Speicherung des gesamten Zustandes hat den Vorteil, daß die Informationen vieler Clientsitzungen auch bei den Clients gespeichert sind und somit für den Server keinen Speicherbedarf bedeuten. Ein Nachteil ist, daß die Information auf der Clientseite eingesehen oder sogar verändert werden kann. Da der Zustand bei jeder Interaktion übertragen werden muß, kann dies bei vielen gleichzeitig aktiven Clients Server und Netz belasten. Ein dritter Nachteil ist, daß keine Statistiken über die einzelnen Zustände herzustellen sind, da die Info bei den Clients gespeichert ist.

Ein Vorteil der serverseitigen Speicherung ist, daß die gesamte Information über alle Clients sicher beim Server aufgehoben ist und auch analysiert werden kann. Positiv ist weiterhin, daß die Zustandsinformation nicht mehr komplett beim User gespeichert wird. Im Folgenden werden einige Möglichkeiten der Zustandsspeicherung vorgestellt.

Zustandsspeicherung über PATH_INFO

Eine Möglichkeit, den Zustand zu erhalten, benutzt die URL. Am Anschluß an den Namen des CGI-Scriptes wird die URL fortgeführt. In obigem Beispiel wäre dies:
                                       https://www.netzmafia.de/cgi-bin/state.pl/1 
                                       https://www.netzmafia.de/cgi-bin/state.pl/2 
                                       https://www.netzmafia.de/cgi-bin/state.pl/3
                                       
usw.

Hier sind /l, /2 und /3 zusätzliche Pfadinformationen, die den Zustand repräsentieren. Innerhalb derselben Browsersitzung kann jeweils durch Anklicken der nächsten dynamisch erzeugten URL zum nächsten Zustand gewechselt werden. Ein Programm gelangt an diese Pfadinformation durch das Auslesen der Umgebungsvariablen PATH_INFO. Wie das geschieht, zeigt folgendes Programm, das auch noch einen weiteren Kniff demonstriert. Über die Umgebungsvariablen SERVER_NAME und SCRIPT_NAME kann man automatisch den WWW-Server und den Pfad zum Skript ermitteln. Damit sind diesbezüglich keine Änderungen von Hand nötig, wenn das Skript auf einem anderen Server laufen soll. Die komplette URL des Skripts ergibt sich aus 'https://' . $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};

                                       #!/usr/bin/perl
                                       # Zustandserhaltung mit PATH_INFO ohne CGI-Modul.
                                       
                                       use strict;
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $url = $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print "Content-type: text/html\n\n";
                                       print "<HTHL>", "\n";
                                       print "<HEAD><TITLE>Status mit Pathinfo</TITLE></HEAD>\n";
                                       print "<BODY>\n";
                                       print "<B>Zustand: ", $state,"</B><P>";
                                       print $saveaction;
                                       print "</BODY></HTML>\n";
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         my $state = $ENV{'PATH_INFO'} || INITSTATE;
                                         $state =~ s/^\///;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $send_me_back = "<A HREF=\"https://$url/$newstate\"> [Weiter] </A>";
                                         return $send_me_back;
                                         }
                                       
Verwendet man das Perl-Modul CGI, wird das Programm einfacher zu schreiben, man sieht aber nicht mehr so genau, was geschieht:
                                       #!/usr/bin/perl
                                       #Zustandserhaltung mit PATH_INFO.
                                       
                                       use strict;
                                       use CGI qw(:standard);
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print header;
                                       print start_html('Status mit Pathinfo');
                                       print '<B>Zustand: ', $state,'</B><P>';
                                       print $saveaction;
                                       print end_html;
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         my $state = $ENV{'PATH_INFO'} || INITSTATE;
                                         $state =~ s/^\///;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $send_me_back = a({-href => url() . "/$newstate"}, , " [Weiter] ");
                                         return $send_me_back;
                                         }
                                       
Nachteil dieser Lösung ist, daß beim Beenden (oder Absturz) des Browsers alle Pfad-Info verloren ist. Weiterhin kann der Benutzer in der URL-Zeile des Browser beliebige Angaben machen und so einen beliebigen Zustand eingeben. Durch diese Methode des Session-Tracking können die statischen HTML-Seiten der weiterhin von Internet-Suchmaschinen verarbeitet (indexiert) werden, was eventuell auch nicht erwünscht ist.

URL-Coding per Parameter

Bei dieser Methode wird die SessionID an jede Internet-Adresse (Link) als Parameter angehängt (z. B. https://www.server.de/cgi-bin/forum.cgi?state=4). Der Wert des Parameters wird dann per GET-Methode geholt. Die Seitenabrufe sehen dann beispielsweise so aus:
                                       https://www.netzmafia.de/cgi-bin/state.pl
                                       https://www.netzmafia.de/cgi-bin/state.pl?state=2 
                                       https://www.netzmafia.de/cgi-bin/state.pl?state=3
                                       
usw.

Das Programm gleicht fast dem vorhergehenden, nur dass hier statt einer Pfadangabe ein Query-String angehängt wird - im Prinzip das, was bei einer Formulareingabe geschieht.

                                       #!/usr/bin/perl
                                       # Zustandserhaltung mit QUERY_STRING.
                                       
                                       use strict;
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my %FORM = ();
                                       my $url = $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print "Content-type: text/html\n\n";
                                       print "<HTHL>", "\n";
                                       print "<HEAD><TITLE>Status mit Query-String</TITLE></HEAD>\n";
                                       print "<BODY>\n";
                                       print "<B>Zustand: ", $state, "</B><P>";
                                       print $saveaction;
                                       print "</BODY></HTML>\n";
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         &parse_form;
                                         my $state = $FORM{'state'} || INITSTATE;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $send_back = "<A HREF=\"https://$url?state=$newstate\"> [Weiter] </A>";
                                         return $send_back;
                                         }
                                       
                                       sub parse_form 
                                         {
                                         my ($buffer, @pairs, $pair, $name, $value);
                                         $buffer = $ENV{'QUERY_STRING'};
                                         @pairs = split(/&/, $buffer);
                                         foreach $pair (@pairs)
                                           {
                                           ($name, $value) = split(/=/, $pair);
                                           $value =~ tr/+/ /;
                                           $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                                           $FORM{$name} = $value;
                                           }
                                         }
                                       
Auch hier die Alternative mit dem CGI-Modul. Nun fällt z. B. die Parse-Routine weg:
                                       #!/usr/bin/perl
                                       # Zustandserhaltung mit QUERY_STRING.
                                       
                                       use strict;
                                       use CGI qw(:standard);
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print header;
                                       print start_html('Status mit Query-String');
                                       print '<B>Zustand: ', $state,'</B><P>';
                                       print $saveaction;
                                       print end_html;
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         my $state = param('state') || INITSTATE;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $send_back = a({-href => url() . "?state=$newstate"}, " [Weiter] ");
                                         return $send_back;
                                         }
                                       
                                       
Auch bei dieser Methode kann der Benutzer den Zustand beliebig ändern. Trotzdem wird sie häufig verwendet. Außerdem ist bei einem Beenden/Absturz des Browsers der Status verloren.

Zustand über Hidden-Felder in Formularen

Man codiert den Zustand innerhalb eines Formulars über Felder, die nicht angezeigt werden (<INPUT TYPE="HIDDEN" ...>>). Sie werden vom Browser generiert und mit Information versehen (VALUE=...). Sendet der Benutzer das Formular zurück, wird auch der neue Zustand geliefert. Das folgende Programm zeigt, wie es geht:
                                       #!/usr/bin/perl
                                       #Zustandserhaltung mit Hidden-Feldern.
                                       
                                       use strict;
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my %FORM = ();
                                       my $url = 'https://' . $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print "Content-type: text/html\n\n";
                                       print "<HTHL>", "\n";
                                       print "<HEAD><TITLE>Status mit hidden fields</TITLE></HEAD>\n";
                                       print "<BODY>\n";
                                       print "<B>Zustand: $state </B><P>";
                                       print "<FORM METHOD=\"POST\" ACTION=\"$url\">\n";
                                       print $saveaction;
                                       print '<INPUT TYPE="submit" NAME="submit" VALUE=" Abschicken ">';
                                       print "</FORM>\n";
                                       print "</BODY></HTML>\n";
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         &parse_form;
                                         my $state = $FORM{'state'} || INITSTATE;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $send_back = "<INPUT TYPE=\"hidden\" NAME=\"state\" VALUE=\"$newstate\">";
                                         return $send_back;
                                         }
                                       
                                       sub parse_form 
                                         {
                                         my ($buffer, @pairs, $pair, $name, $value);
                                         if ($ENV{'REQUEST_METHOD'} eq 'GET') 
                                           { @pairs = split(/&/, $ENV{'QUERY_STRING'}); }
                                         elsif ($ENV{'REQUEST_METHOD'} eq 'POST') 
                                           {
                                           @pairs = split(/&/, $buffer);
                                           read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
                                           }
                                         @pairs = split(/&/, $buffer);
                                         foreach $pair (@pairs)
                                           {
                                           ($name, $value) = split(/=/, $pair);
                                           $value =~ tr/+/ /;
                                           $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                                           $FORM{$name} = $value;
                                           }
                                         }
                                       
Die Version mit dem CGI-Modul ist auch hier wieder kürzer:
                                       #!/usr/bin/perl
                                       #Zustandserhaltung mit Hidden-Feldern.
                                       
                                       use strict;
                                       use CGI qw(:standard);
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print header;
                                       print start_html('Status mit Hidden Fields');
                                       print '<B>Zustand: ', $state,'</B><P>';
                                       print '<FORM METHOD="POST">\n';
                                       print $saveaction;
                                       print '<INPUT TYPE="submit" NAME="submit" VALUE=" Abschicken ">';
                                       print '</FORM>\n';
                                       print end_html;
                                       
                                       
                                       sub retrieve_state 
                                         {
                                         my $state = param('state') || INITSTATE;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         
                                         my $send_back = '<INPUT TYPE="hidden" NAME="state" VALUE=';
                                         $send_back .= "\"$newstate\">";
                                         return $send_back;
                                         }
                                       
Auch bei dieser Methode kann der Benutzer den Zustand beliebig ändern. Trotzdem wird sie ebenso häufig wie die vorstehende verwendet. Außerdem ist auch bei einem Beenden/Absturz des Browsers der Status verloren. Man kann zur Not den Formularcharakter verbergen, wenn der Submit-Button durch ein Bild getarnt wird. Ein Vorteil ist, daß sich mehr Info in der Statusvariablen verbergen läßt.

Zustand über Cookies

Cookies ("Kekse") sind Informationen in Form einfacher ASCII-Texte, die von einem WWW-Server auf dem Rechner des Clients gespeichert und später wieder abgerufen werden können. Der Zustand kann clientseitig gespeichert werden und bei Bedarf von der jeweiligen Dienst-Applikation vom Client wieder abgerufen werden. Cookies sind aber in Verruf geraten, weil sie für User-Tracking verwendet wurden. Sie werden deshalb gerne im Browser deaktiviert und garantieren somit kein durchgängiges Session-Tracking, obwohl sie von Netscape eigens für diesen Zweck konzipiert worden sind. Sie stellen jedoch kein Sicherheitsrisiko dar. Session-Tracking über Cookies stellt die einfachste Methode dar und findet auch bei vielen Anwendungen Verwendung. Ganz Allgemein: Cookies sind Dateien, die auf dem Rechner des Clients abgelegt und von Prozessen auf dem Server (CGI) ausgelesen werden können. Das Anlegen eines Cookies erfolgt durch serverseitiges Senden der entsprechende HTTP-Header an den Browser. In einem solchen Header sind bereits alle Informationen des Cookies enthalten. Cookies können also dazu dienen, zwischen einem serverseitigen Prozess und einem bestimmten Client Informationen auszutauschen.

Beispielsweise füllt der Client ein Formular aus und schickt es an den Server.Das verarbeitwende CGI-Skript schickt in der Antwortseite einen Cookie an den Client mit. Ruft der Client innerhalb der Verfallszeit des Cookies dieses Formular erneut auf, sorgt die im Cookie abgelegte und nunmehr vom CGI-Skript ausgelesene Information dafür, daß der Client das Formular bereits ausgefüllt in seinem Browser vorfindet.

Ein Browser kann nicht mehr als 300 Cookies speichern, wobei ein Cookie nicht größer als 4 KByte sein darf. Die Anzahl der Cookies eines Servers ist auf 20 begrenzt.

Die wichtigsten Parameter eines Cookies:

  • name=wert
    Dieses Paar wird bei der Abfrage des Cookies zurückgeliefert. Der Wert darf keine Strichpunkte, Kommata, Leerzeichen, Tabulatoren usw. enthalten.
  • expires=datum
    Verfallsdatum des Cookies. Fehlt dieser Wert, "lebt" das Cookie nur für die Dauer der Browser-Session. Das Datum besitzt das Format Wochentag, DD-Mon-YYYY HH:MM:SS GMT.
  • path=pfad
    Das Cookie wird an den Server gesendet, sobald auf eine Datei im angegebenen Pfad (ausgehend von der DocumentRoot) zugegriffen wird. Die Angabe ist optional.
  • domain=domäne
    Beschränkt den Abruf des Cookies auf die Server der angegebenen Domäne. Teilangaben sind möglich, z.B. nur die Top- und Second-Level-Domain. Die Angabe ist optional.

Das folgende Programm zeigt, wie Cookies eingesetzt werden. Die Cookies werden netterweise schon in der Umgebungsvariablen HTTP_COOKIE bereitgestellt. Das Setzen eines Cookies erfolgt im HTTP-Header. Es muß daher vor der Zeile Content-type: text/html stehen! Die Zeile zum Setzen eines Cookies hat folgenden Aufbau:

                                       Set-Cookie: Name=Wert, expires=Datum, path=Pfad, domain=Domain
                                       
Die Felder sind also durch Strichpunkt getrennt. Wie oben angedeutet dürfen optionale Felder auch fehlen.
                                       #!/usr/bin/perl
                                       #Zustandserhaltung mit Cookies.
                                       
                                       use strict;
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $url = $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
                                       my $Cookie_Domain = $ENV{'SERVER_NAME'};
                                       my $ExpDate = "Monday, 31-Dec-2035 23:59:59 GMT"; # cookie expire date
                                       
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print "Content-type: text/html\n\n";
                                       print "<HTHL>", "\n";
                                       print "<HEAD><TITLE>Status mit Cookies</TITLE></HEAD>\n";
                                       print "<BODY>\n";
                                       print '<B>Zustand: ', $state,'</B><P>';
                                       print "Bitte 'Reload Page' betätigen";
                                       print "</BODY></HTML>\n";
                                       
                                       sub retrieve_state 
                                         {
                                         # must be before "content-type"-line
                                         my $state = &GetMakeCookie;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         SetCookie("State", $newstate, $ExpDate, "/", $Cookie_Domain);
                                         }
                                       
                                       sub SetCookie
                                         {
                                         my ($name, $val, $exp, $path, $dom) = @_;
                                         print "Set-Cookie: ";
                                         print "$name=$val, expires=$exp, path=$path, domain=$dom\n";
                                         }
                                       
                                       sub GetCookies
                                         {
                                         my %cookies;
                                         my $cookie;
                                         foreach $cookie (split (/; /,$ENV{'HTTP_COOKIE'}))
                                           {
                                           my($key) = split(/=/, $cookie);
                                           $cookies{$key} = substr($cookie, index($cookie, "=")+1);
                                           }
                                         return(%cookies);
                                         }
                                       
                                       sub GetMakeCookie
                                         {
                                         my $State = '';
                                         my %Cookies = GetCookies();
                                         $State = $Cookies{'State'};
                                         $State =~ s/,.*//;
                                         # No Cookie Data? Establish one!
                                         if ($State eq '')
                                           {
                                           $State = INITSTATE;
                                           SetCookie("State", $State, $ExpDate, "/", $Cookie_Domain);
                                           }
                                         return($State);
                                         }   
                                       
Will man nicht nur unseren Beispiel-Status, sondern etwa eine Kunden-Kennung speichern, sollte der Wert anders gewählt werden. Da sich der Kunde eventuell noch gar nicht angemeldet hat, fallen Kundennummern etc. weg. Andererseits sollten die vergebenen Kennungen einmalig sein, sonst vermischen sich zwei Bestellungen. Die folgende Variation der Funktion GetMakeCookie schliesst so etwas nicht aus, ist aber hinreichend variabel. Sie nimmt den aktuellen UNIX-Zeitstempel und zwei Zufallszahlen. Damit sind auch Kunden unterscheidbar, die sich in der gleichen Sekunde anmelden. Ausserdem verschleiern die Zufallszahlen den Zeitstempel:
                                       sub GetMakeCookie
                                         {
                                         my %Cookies = ();
                                       
                                         $Customer = '';
                                         %Cookies = GetCookies();
                                         $Customer = $Cookies{'Customer'};
                                         $Customer =~ s/,.*//;
                                         # No Cookie Data? Establish one!
                                         if ($Customer eq '')
                                           {
                                           srand(time % 1000);
                                           $Customer = int(rand(999)) . time() . $$ . int(rand(999));
                                           SetCookie("Customer", $Customer, $ExpDate, "/", $Cookie_Domain);
                                           }
                                         }   
                                       
Das war jetzt die händische Lösung. Dank des Moduls CGI::Cookie ist die Cookie-Programmierung aber genauso einfach, wie die anderen gezeigten Methoden. Das folgende Programm zeigt die Anwendung des Moduls:
                                       #!/usr/bin/perl
                                       #Zustandserhaltung mit Cookies.
                                       
                                       use strict;
                                       use CGI qw(:standard);
                                       use CGI::Cookie;
                                       
                                       use constant INITSTATE => 1;
                                       
                                       my $state      = retrieve_state();
                                       my $nextstate  = compute_next_state($state);
                                       my $saveaction = save_state($nextstate);
                                       
                                       # Tue etwas abhaengig von $state:
                                       print header(-cookie => $saveaction);
                                       print start_html('Status mit Cookies');
                                       print '<B>Zustand: ', $state,'</B><P>';
                                       print "Bitte 'Reload Page' bet&auml;tigen";
                                       print end_html;
                                       
                                       sub retrieve_state 
                                         {
                                         my $state = cookie(-name => 'state') || INITSTATE;
                                         return $state;
                                         }
                                       
                                       sub compute_next_state 
                                         {
                                         my $current_state = shift;
                                         return $current_state + 1;
                                         }
                                       
                                       sub save_state 
                                         {
                                         my $newstate = shift;
                                         my $cookie   = new CGI::Cookie(-name    => 'state',
                                       				                 -value   => $newstate,
                                       			                     -expires => '+5m'); 
                                       			                     # diesmal nur 5 Minuten Haltbarkeit
                                         return $cookie;
                                         }
                                       
Das Cookie wird im Header der HTTP-Antwort des Servers übermittelt. Es darf auch höchstens einige hundert Bytes lang werden. Auch hat jeder Bowser eine Obergrenze für die Anzahl der verwalteten Cookies. Auch können erfahrene Benutzer durch Editieren der Datei cookies.txt auch die Statusinformation im Cookie verändern. Da würde es nur helfen, die Cookie-Information zu verschlüsseln oder mit einer Signatur zu versehen.

Session-Cookies

Die Session-Cookies sollen den Benutzer für die Dauer einer Session (Terminal-Sitzung) identifizieren, z. B. bei einem Datenbank-Interface per CGI-Skript oder auch bei einem Spiel. Das funktioniert folgendermaßen:
  1. Anmeldung
    Der Benutzer gibt seine Benutzerkennung und sein Passwort in ein Web-Formular ein. Über irgendein Protokoll (NIS, LDAP, usw.) oder eine Datenbankabfrage erfolgt die Authentifizierung.

  2. Session-Aufbau
    Bei erfolgreicher Anmeldung erzeugt der serverseitige Prozess eine eindeutige ID, die einmal in einem Cookie des Benutzers und gleichzeitig in einer Datenbank auf dem Server abgelegt wird.

  3. Session aktiv
    Solange es das Paar (ID im Cookie == ID in der Datenbank) gibt gilt die Session als aktiv und der Benutzer als authentifiziert. Bei jedem Kommando des Benutzers wird nicht jedesmal eine neue Authentifizierung vorgenommen sondern lediglich geprüft ob die Session noch gültig ist.

Über ein solches Session-Cookie lassen sich beliebige andere Systeme abwickeln, zum Beispiel ein Warenkorbsystem oder das Speichern von Spielständen: Die im Cookie gespeicherte ID ist der primärer Schlüssel für bestimmte Tabellen, in denen benutzerspezifische Informationen serverseitig abgelegt sind. Alle Eingaben des Benutzers werden nicht im Cookie sondern unter der Verwendung der ID in der Server-Datenbank gespeichert. Das Cookie enthält nur noch die ID und ist nur in einer Browsersitzung gültig.

Problem: Erzeugen einer eindeutigen ID

Echte Zufälle gibt es in der EDV nicht. Selbst die Perl-Funktion rand() ermittelt eine Zufallszahl aus irgendwelchen anderen Parametern - die nicht zufällig sind. Erst wenn man einen solchen "Zufallswert" mit MD5 oder crypt verschlüsselt, ist die Wahrscheinlichkeit gering, daß es mehrere gleiche Ergebnisse gibt. Es gibt verschiedene Möglichkeiten, einen eindeutigen String zu erzeugen, z. B. das Einbeziehen der Zeit (siehe Beispiel oben). Eine andere Möglichkeit zeigt das folgende Programmstück. Der String time.$$ (Sekunden seit der UNIX-Epoche und die Prozess-ID) wird mit einem zufälligen saltder Crypt-Funktion verschlüsselt
                                       # Session-ID generieren
                                       sub make_id
                                         {
                                         # salts erzeugen
                                         my @salts = ('a'..'z');
                                         shuffle(\@salts);
                                         my $salt = join ("", @salts);
                                         my $random = crypt($salt,time.$$);
                                         return $random;
                                         }
                                       
                                       # Eine Menge mischen (siehe PERL-Dokumentation: fisher_yates_shuffle)
                                       sub shuffle
                                         {
                                         my $array = shift;
                                         my ($i, $j);
                                         for ($i = @$array; --$i;)
                                           {
                                           $j = int (rand($i+1));
                                           next if ($i == $j);
                                           @$array[$i,$j] = @$array[$j,$i];
                                           }
                                         }
                                       

Neben crypt gibt es auch noch andere Methoden zur Einweg-Verschlüsselung, z. B. MD5 (siehe unten).

Nicht mehr benutzte Einträge löschen

Aufgrund der Tatsache, dass es nicht möglich ist, festzustellen, wann ein Client seinen Browser geschlossen hat, kann es vorkommen, daß in der Session - Datenbank unbenutzte Einträge zurückbleiben. Auf jeden Fall sollte dem Benutzer ein Button oder ein Link angeboten werden, mit dem er sich auszuloggen kann. Das Ausloggen löscht alle Einträge sowie den Key in der Session-Datenbank des Servers.

Was jedoch, wenn der Benutzer sich nicht ausloggt? Dann bieten sich folgende Möglichkeiten an:

  • Gültigkeitsdauer einer Session festlegen
    Zu einer Session wird die Eröffnungszeit festgehalten. In jedem zur Session gehörigen Prozess wird geprüft ob dieser Zeitstempel innerhalb eines gültigen Bereichs liegt. Auf diese Art kann eine Session auf beispielsweise 30 Minuten begrenzt werden.
  • Gültigkeitsdauer generell festlegen
    Auch hier wird beim Erzeugen einer Session ein Timestamp in der DB abgelegt. Ein per cron gesteuerter Prozess prüft regelmßig, ob es in der Session-Datenbank Einträge gibt, die bestimmten Zeitkriterien nicht mehr genügen - so können beispielsweise alle Einträge gelöscht werden, die älter als ein Tag sind.

DIPLOMARBEITEN UND BÜCHER

Diplomarbeiten zum Runterladen:

Suche im Katalog:
Architektur / Raumplanung
Betriebswirtschaft - Funktional
Erziehungswissenschaften
Geowissenschaften
Geschichtswissenschaften
Informatik
Kulturwissenschaften
Medien- und Kommunikationswissenschaften
Medizin
Psychologie
Physik
Rechtswissenschaft
Soziale Arbeit
Sozialwissenschaften


JOBS
HOME | E-LEARNING | SITEMAP | LOGIN AUTOREN | SUPPORT | FAQ | KONTAKT | IMPRESSUM
Virtual University in: Italiano - Français - English - Español
VirtualUniversity, WEB-SET Interactive GmbH, www.web-set.com, 6301 Zug

Partner:   Seminare7.de - PCopen.de - HTMLopen.de - WEB-SET.com - YesMMS.com - Ausbildung24.ch - Manager24.ch - Job und Karriere