Solero: Logoutproblem mit Session-Variablen

Hallo Leute,

leider weiss ich noch gar nicht so genau, wo mein Problem liegt und hoffe deshalb, dass die Thematik stimmt^^ Ich werde es euch einfach mal schildern und hoffe, dass ihr damit etwas anfangen könnt. Danke schonmal im Voraus!

Meine Homepage hat einen Internen Bereich mit selbstgebasteltem Login-Script. Die Clou des ganzen ist, dass bei korrektem Einloggen folgender Code abläuft:

  
//Einloggen  
if ( /*Passwort und Benutzer korrekt*/ && !$_SESSION['login']) {  
session_start();  
$_SESSION['login'] = TRUE;  
}  

Das funktioniert soweit einwandfrei, man kann sich einloggen und über die Abfrage

  
session_start();  
if (!$_SESSION['login']) { require 'loginformular.html'; }  
else { require 'interner_bereich.php'; }  

auf den internen Bereich zugreifen, dort wild im Angebot hin und her browsen, sich mit folgendem Code ausloggen ~~~php

//Ausloggen
session_start();
if ($_GET['logout'] && $_SESSION['login']) {
$_SESSION['login'] = FALSE;
}

und wieder einloggen. Funktioniert immer einwandfrei.  
  
Das Problem beginnt dann (und nur mit Firefox, nich mit IE!) wenn man eingeloggt ist und auf eine Seite des nicht-internen-Bereichs meiner Homepage zugreift. Sobald man nämlich wieder auf den internen Bereich wechseln will, wird mit dem zweiten Code-Beispiel das Login-Formular aufgerufen, wer sich dann aber erneut einloggen will, kommt nicht an der Abfrage im "Login-Scipt" vorbei, die ja (siehe erster Code) überprüft, ob man nicht schon eingeloggt ist.  
  
Ich kann das Problem lösen, indem ich beim "Login-Script" die Abfrage nach "bereits eingeloggt" entferne, und es somit zulasse, dass sich jemand zweimal einloggt. Ist grundsätzlich (noch) kein Problem, aber ich verstehe nicht, wieso die grundsätzlich selbe If-Abfrage zwei verschiedene Ergebnisse liefert. Könnt ihr mir da helfen?  
  
MfG  
Solero
  1. Om nah hoo pez nyeetz, Solero!

    if ($_GET['logout']

    unbehandelte $_GET-Variablen sind ein Sicherheitsrisko.

    Könnt ihr mir da helfen?

    http://wiki.selfhtml.org/wiki/Technische_Ergänzungen/Loginsystem

    Matthias

    --
    1/z ist kein Blatt Papier.

    1. if ($_GET['logout']

      unbehandelte $_GET-Variablen sind ein Sicherheitsrisko.

      Was meinst du mit "unbehandelt"? Mir ist bewusst, dass sich jemand von meinem internen Bereich ausloggen kann, indem er einfach die Datei logout.php?logout=1 aufruft, anstatt auf meinen Logout-Button zu klicken, der dann genau das selbe macht. Das "logout-Script" läuft aber nur ab, wenn jemand eingeloggt ist (siehe mein Code), ich kann mir deshalb nicht vorstellen, wo dabei ein Sicherheitsrisiko entsteht. Bin aber absolut neu auf diesem Terrain!

      Könnt ihr mir da helfen?

      http://wiki.selfhtml.org/wiki/Technische_Ergänzungen/Loginsystem

      Habe ich durchgelesen, der einzige effektive Unterschied zwischen diesem Loginsystem und meinem besteht meiner Meinung nach in der Abfrage, ob jemand eingeloggt ist:

        
      //Meine Version  
      session_start();  
      if (!$_SESSION['login']) { /* Hier ist die Weiterleitung fuer eingeloggte */ }  
        
      //Version Loginsytem  
      if (!isset($_SESSION['angemeldet']) || !$_SESSION['angemeldet']) { /* Hier ist die Weiterleitung fuer eingeloggte */ }  
      
      

      Habe das bei mir geändert, dass Problem besteht aber nach wievor...

      MfG
      Solero

      1. Hallo,

        if ($_GET['logout']
        unbehandelte $_GET-Variablen sind ein Sicherheitsrisko.
        Was meinst du mit "unbehandelt"?

        "unbehandelt" heißt in diesem Zusammenhang: Nicht auf Gültigkeit geprüft.

        Mir ist bewusst, dass sich jemand von meinem internen Bereich ausloggen kann, indem er einfach die Datei logout.php?logout=1 aufruft, anstatt auf meinen Logout-Button zu klicken, der dann genau das selbe macht.

        Wenn das die einzigen Konsequenzen sind und du dir darüber im Klaren bist, ist alles okay. Es ging Matthias wohl eher um eine grundsätzliche Sache, weil das ungeprüfte Verwenden von Benutzereingaben häufig Ursache für Fehler, teilweise schwerwiegende Fehler ist.

        Solange du aber entweder Falscheingaben ausschließt, oder -wie in diesem Fall- die Auswirkung von nicht vorgesehenen Aktionen überblicken und für harmlos erklären kannst, ist das in Ordnung.

        Ciao,
         Martin

        --
        Wenn der Computer wirklich alles kann,
        dann kann er mich mal kreuzweise.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
    2. if ($_GET['logout']

      unbehandelte $_GET-Variablen sind ein Sicherheitsrisko.

      Nana. Hier wird $_GET['logout'] lediglich darauf geprüft, ob es einen wahren Wert enthält. So lange es nicht weiter verwendet wird ist eine Behandlung obsolet, weil selbst bei einem $_GET['logout']="Hier steht was ganz böses!", nichts anderes passiert, als dass eine Session-Variable auf FALSE gesetzt wird. Ein Sicherheitsrisiko ist an dieser Stelle nicht erkennbar.

      fred

    3. Tach!

      if ($_GET['logout']
      unbehandelte $_GET-Variablen sind ein Sicherheitsrisko.

      Das kann man so pauschal nicht sagen. Richtiger wäre: Beim Ausgeben den Kontext nicht zu beachten ist ein Sicherheitsrisiko. Dabei ist es vollkommen egal, ob das eine Benutzereingabe ist, ob sie es vor langer Zeit einmal war oder ob es was ganz anderes ist.

      In dem Fall ist das lediglich eine Prüfung auf ihren Inhalt, was völlig harmlos ist. Lediglich die Notice-Meldung, falls der Wert nicht existiert, wäre beanstandenswert - beziehungsweise die unterlassene Prüfung auf Existenz.

      Könnt ihr mir da helfen?

      Wenn der Firefox ein anderes Ergebnis bringt, ist irgendein Wert anders als erwartet. Da helfen erstmal nur Debug-Ausgaben, um den unerwarteten Wert zu finden (mit var_dump()). Anschließend erst kann man sich ernsthaft Gedanken machen, warum das so ist.

      dedlfix.

      1. Hallo zusammen

        Womöglich wird die IF-Abfrage gar nicht ausgeführt, weil das PHP-Skript gar nicht ausgeführt wird. Für mich sieht es so aus, als solltest Du vor allem nach header() und caching schauen. Ich vermute nämlich, Du bekommst im Firefox den Browser-Cache mit dem Login angezeigt.

        Die If-Abfrage wird definitiv ausgeführt, ich liess in ihr zusätzlich via PHP etwas ausgeben, was angezeigt wurde, der Browser lud die Seite also nicht aus dem Cache.

        Ich vermute ergo, dass diese beiden Zeilen (vor allen anderen Zeilen!) Dein Problem beheben:

        header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1

        header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Datum in der Vergangenheit!

          
        Habe ich natürlich trotzdem ausprobiert, um sicher zu gehen, hat aber das Problem nicht gelöst.  
          
        
        > Wenn der Firefox ein anderes Ergebnis bringt, ist irgendein Wert anders als erwartet. Da helfen erstmal nur Debug-Ausgaben, um den unerwarteten Wert zu finden (mit var\_dump()). Anschließend erst kann man sich ernsthaft Gedanken machen, warum das so ist.  
          
        Das war definitiv ein Tipp in die richtige Richtung!  
        Nach erfolgreichen Logout erhalte ich durch `var_dump($_SESSION['login']);`{:.language-php} richtigerweise bool(false) und nach erfolgtem Login bool(true), insoweit also korrekt.  
        Wenn ich zusammen mit dem Loginscript `var_dump($_SESSION['login']);`{:.language-php} ausgebe, erhalte ich zum Zeitpunkt wo das Loginscript fälschlicherweise aufgerugen wird den Wert NULL, PHP ruft es also richtigerweise auf, da  
        `if (!$_SESSION['login'] or !isset($_SESSION['login']))`{:.language-php} zutrifft.  
          
        Gebe ich aber nun in die Adresszeile des Browser die URL einer Seite im internen Bereich ein, erhalte ich Zugriff und es wird bool(true) ausgegeben, obwohl ich dem Server \_keine\_ Logindaten gesendet habe!  
          
        Das Problem ist also, wieso wechselt der Server scheinbar willkürlich den Wert von `$_SESSION['login']`{:.language-php} von TRUE auf NULL und wieder zurück?  
          
        MfG  
        Solero
        
        1. Wenn ich zusammen mit dem Loginscript var_dump($_SESSION['login']); ausgebe, erhalte ich zum Zeitpunkt wo das Loginscript fälschlicherweise aufgerugen wird den Wert NULL, PHP ruft es also richtigerweise auf, da
          if (!$_SESSION['login'] or !isset($_SESSION['login'])) zutrifft.

          Also in dieser Situation rate ich zu einem Mittagsschläfchen. Vermutlich machst Du - und diese Erfahrung habe mit mir selbst gemacht - aktuell mehr kaputt wenn Du jetzt weiter machst. Danach geht es regelmäßig besser.

          fred

        2. Tach!

          Nach erfolgreichen Logout erhalte ich durch var_dump($_SESSION['login']); richtigerweise bool(false) und nach erfolgtem Login bool(true), insoweit also korrekt.
          Wenn ich zusammen mit dem Loginscript var_dump($_SESSION['login']); ausgebe, erhalte ich zum Zeitpunkt wo das Loginscript fälschlicherweise aufgerugen wird den Wert NULL, PHP ruft es also richtigerweise auf, da
          if (!$_SESSION['login'] or !isset($_SESSION['login'])) zutrifft.

          Du hast dein error_reporting nicht auf E_ALL stehen (und/oder display_errors auf off), so dass dir die Notice-Meldungen entgehen. Wenn du auf Variablen (oder Array-Elemente) zugreifen willst, von denen du nicht absolut sicher weißt, dass sie existieren, muss zuerst das isset() verwenden und dann weitere Test in Abhängigkeit davon durchführen. Alternativ geht auch empty(), das ebenfalls keine Notice-Meldungen bei nicht vorhandenen Variablen wirft.

          Das NULL bedeutet garantiert, dass die Variable nicht vorhanden ist. Prüf das mit einem E_ALL-error_reporting. Wie lautet die Fehlermeldung? "Undefined variable: _SESSION" oder "Undefined index ..."?

          Gebe ich aber nun in die Adresszeile des Browser die URL einer Seite im internen Bereich ein, erhalte ich Zugriff und es wird bool(true) ausgegeben, obwohl ich dem Server _keine_ Logindaten gesendet habe!

          Eine Session läuft über die Session-ID. Wenn die nicht in der URL übertragen wird, dann als Cookie in den HTTP-Headern. Schau dir diese an. Die Browser haben dazu eingebaute Tools oder es lassen sich solche nachrüsten: z.B. livehttpheaders-Extension für den Firefox.

          Das Problem ist also, wieso wechselt der Server scheinbar willkürlich den Wert von $_SESSION['login'] von TRUE auf NULL und wieder zurück?

          Er wechselt nicht willkürlich, sondern weil er mal Session-Daten hat und mal keine - vermutlich. Die Session-ID auszugeben kann auch für Aufklärung sorgen.

          dedlfix.

        3. Hallo,

          if (!$_SESSION['login'] or !isset($_SESSION['login']))

          die beiden Einzel-Abfragen solltest du umgekehrt formulieren - die isset()-Abfrage immer zuerst. Von der boolschen Logik her ist es dasselbe, aber PHP arbeitet logische Verknüpfungen von links nach rechts ab und bricht die Auswertung ab, sobald das Ergebnis feststeht. Deswegen prüft man *zuerst* auf Vorhandensein einer Variablen mit !isset(), und wenn das zutrifft (die Variable nicht existiert), dann greift PHP gar nicht mehr auf den Variablenwert zu. In deinem Fall erfolgt aber auf jeden Fall erst ein Zugriff auf den Variablenwert, der fehlschlagen kann (dann wird idR eine Notice-Meldung ausgegeben), und die Prüfung auf Vorhandensein ist dann sinnlos.

          Das Problem ist also, wieso wechselt der Server scheinbar willkürlich den Wert von $_SESSION['login'] von TRUE auf NULL und wieder zurück?

          Du übermittelst die Session ID doch bestimmt in einem Cookie, oder? Bist du sicher, dass du immer dieselbe Session verwendest? Könnte es nicht sein, dass der IE in bestimmten Fällen das Cookie mit der Session ID nicht ordentlich vorzeigt? Steht wirklich immer die richtige Session ID in $COOKIE[]?

          So long,
           Martin

          --
          Ich verdanke meinen Eltern so viel - besonders meiner Mutter und meinem Vater.
            (Dakota Fanning, US-Nachwuchsschauspielerin)
          Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
  2. Hallo Solero,

    //Einloggen
    if ( /Passwort und Benutzer korrekt/ && !$_SESSION['login']) {
    session_start();
    $_SESSION['login'] = TRUE;
    }

    
    > Das funktioniert soweit einwandfrei, man kann sich einloggen und über die Abfrage  
      
    Deine Abfrage sieht für mich ungewöhnlich aus. Wenn man den Kommentar entfernt steht dort:  
      
    
    > ~~~php
      
    
    > if ( && !$_SESSION['login']) {  
    > 
    
    

    War das eine linke Seite der Und-Verknüpfung geplant? Oder ist das ein Copy-Paste-Fehlerteufelchen? Vermutlich sollte der Kommentar durch die entsprechenden Anweisungen ersetzt werden. Das könnte die teils ungewöhnlichen Reaktionen erklären.

    ciao
    romy

    1. Hallo romy,

      //Einloggen
      if ( /Passwort und Benutzer korrekt/ && !$_SESSION['login']) {
      session_start();
      $_SESSION['login'] = TRUE;
      }

      
      > > Das funktioniert soweit einwandfrei, man kann sich einloggen und über die Abfrage  
      >   
      > Deine Abfrage sieht für mich ungewöhnlich aus. Wenn man den Kommentar entfernt steht dort:  
      >   
      > > ~~~php
        
      
      > > if ( && !$_SESSION['login']) {  
      > > 
      
      

      War das eine linke Seite der Und-Verknüpfung geplant? Oder ist das ein Copy-Paste-Fehlerteufelchen? Vermutlich sollte der Kommentar durch die entsprechenden Anweisungen ersetzt werden. Das könnte die teils ungewöhnlichen Reaktionen erklären.

      »»

      Habe dort lediglich einen Kommentar gesetzt, weil in meinem Script an dieser Stelle eine DB-Abfrage nach dem Passwort via md5, Vergleich mit dem eingegebenen Passwort usw steht.
      Das "Einloggen" hat aber immer einwandfrei funktioniert, d.h. das Passwort wurde akzeptiert, weshalb ich euch diesen (funktionierenden) Code-Teil ersparen wollte. Hätte ich wohl etwas besser formulieren müssen. Sorry!

      MfG
      Solero

      1. Hallo Solero,

        Das "Einloggen" hat aber immer einwandfrei funktioniert, d.h. das Passwort wurde akzeptiert, weshalb ich euch diesen (funktionierenden) Code-Teil ersparen wollte. Hätte ich wohl etwas besser formulieren müssen. Sorry!

        Ah ja, kein Problem. Ich verstehe das so, dass wenn du wieder in den internen Bereich willst die Session-Variable $_SESSION['login'] fälschlicherweise ein FALSE zurückgibt? Sobald aber zur Login-Seite gewechselt wird, wieder ein TRUE drin steht. Richtig?

        ciao
        romy

        1. Hallo romy,

          Ah ja, kein Problem. Ich verstehe das so, dass wenn du wieder in den internen Bereich willst die Session-Variable $_SESSION['login'] fälschlicherweise ein FALSE zurückgibt? Sobald aber zur Login-Seite gewechselt wird, wieder ein TRUE drin steht. Richtig?

          Wenn du das so schreibst wirkt es relativ unwahrscheinlich, aber irgendwie scheint auf meiner Homepage genau das zu passieren, sofern diese Schritte mit Firefox unternommen werden, beim IE besteht nach wie vor kein Problem.
          Erklären kann ich es mir nach wie vor nicht...

          MfG
          Solero

          1. Hallo Solero,

            Wenn du das so schreibst wirkt es relativ unwahrscheinlich, aber irgendwie scheint auf meiner Homepage genau das zu passieren, sofern diese Schritte mit Firefox unternommen werden, beim IE besteht nach wie vor kein Problem.
            Erklären kann ich es mir nach wie vor nicht...

            Ich mir leider auch nicht, aber Freds Antwort dürfte in die richtige Richtung gehen!? Hilft sein Vorschlag mit den Headern?

            ciao
            romy

  3. Ist grundsätzlich (noch) kein Problem, aber ich verstehe nicht, wieso die grundsätzlich selbe If-Abfrage zwei verschiedene Ergebnisse liefert. Könnt ihr mir da helfen?

    Womöglich wird die IF-Abfrage gar nicht ausgeführt, weil das PHP-Skript gar nicht ausgeführt wird. Für mich sieht es so aus, als solltest Du vor allem nach header() und caching schauen. Ich vermute nämlich, Du bekommst im Firefox den Browser-Cache mit dem Login angezeigt.

    Ich vermute ergo, dass diese beiden Zeilen (vor allen anderen Zeilen!) Dein Problem beheben:

    header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1  
    header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Datum in der Vergangenheit!
    
    1. Tach!

      header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Datum in der Vergangenheit!

      Hier würde ich kein wirkliches Datum sondern nur 0 verwenden. Ein Datumswert könnte unkommentiert zu Missverständnissen führen. Bei 0 ist hingegen eindeutig festgelegt:

      HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired").

      dedlfix.

      1. HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired").

        Nun, das Beispiel ist auch für veraltete HTTP 1.0 - Clients gedacht. Anders als bei HTTP 1.1 wird in der Spezifikation für HTTP 1.0 dieses Verhalten nur wärmstens empfohlen:

        Note: Applications are encouraged to be tolerant of bad or misinformed implementations of the Expires header. A value of zero (0) or an invalid date format should be considered equivalent to an "expires immediately." Although these values are not legitimate for HTTP/1.0, a robust implementation is always desirable.