• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Loginsystem: Letzte Aktivität prüfen, nach xx Minuten ausloggen

aJunkie

Mitglied
Halli Hallo,

ich habe 'en Script und wollte da eine Abfrage einbauen, der schaut, wann die letzte Aktivität (neuer Request) des Users war und wenn diese 30 Minuten zurückliegt, soll die Session unsettet werden.
session.gc_maxlifetime habe ich schon versucht, klappt aber auf XAMPP nicht. Ich hoffe, dass das am Dateisystem liegt.

Jedenfalls möchte ich es noch selbst machen:

PHP:
<?php 
// Dieser Script wird in jede Datei includet, die geschützt werden soll

session_start();
include('db.php');    # Datenbankverbindung
include_once('funktionenundso.inc.php'); # Funktionen

# ausloggen
if(isset($_GET['logout'])) logout();


# Login überprüfen
    # prüft Sessionvariablen und ob die IP Adresse des Einloggers mit dem aktuellen User übereinstimmt (Session Hijacking vermeiden)
if($_SESSION['eingeloggt'] && $_SESSION['user'] && $_SESSION['ip'] == md5(strrev($_SERVER['REMOTE_ADDR']))) {
    
    # Letzte Aktivität des Users checken
    $LastActivityQ    = mysql_query("SELECT lastActivity FROM `logins` WHERE user = '".$_SESSION['user']."' LIMIT 1");
    $LastActivityR    = mysql_fetch_row($LastActivityQ);
# Hier hole ich 'lastActivity' aus der Datenbank. $LastActivityR ist nun aber ein Array.

# wie sollte ich hier nun am besten prüfen?!

# wenn die letzte Aktivität nicht zu lange her ist, wird hier dann die Sessionlebensdauer aktualisiert (in DB geschrieben)
    mysql_query("UPDATE `logins` SET lastActivity = NOW() WHERE user = '".$_SESSION['user']."' LIMIT 1"); # Letzte Aktivität in DB speichern
    
} else {    # Login false
    logout();
}

# ansonsten, wenn also eingeloggt, alles in bester Ordnung und die Datei ist sichtbar.
?>
NOW() speichert ja kein Timestamp.

Ich möchte nur "automatisch" ausloggen lassen, weil es vorkommt, dass der Browser einfach geschlossen wird.

Edit: Erledigt, aber neue Fragen in folgenden Posts.
 
Zuletzt bearbeitet:
Werbung:
Man kann glaub so weit ich weiss 2 Daten in mysql über TIMESTAMPDIFF miteinander vergleichen.
Suche dort mal nach TIMESTAMPDIFF: MySQL :: MySQL 5.1 Referenzhandbuch :: 12.5 Datums- und Zeitfunktionen
Du fragst einfach in einer query wo ein User eingeloggt ist und die letzte Aktivität über 30 min her ist.
Kann sein dass es falsch ist aber teste mal folgendes:
Code:
 SELECT `id` FROM `logins` WHERE `loggedIn` = 'true' AND TIMESTAMPDIFF(MINUTE, `lastActivity`, NOW()) >= 30;
Teste mal aus, was er dir sagt. Kann sein, dass NOW in ein date umgewandelt werden muss. Weiß es nicht genau. Aber der Ansatz sollte richtig sein ;)
 
Danke. Aber waaah... wird ja umständlicher.

Ich speicher einfach alles in timestamp, so wird die Abfrage auch einfacher.

Mal angenommen:
PHP:
# wenn die letzte Aktivität nicht zu lange her ist, wird hier dann die Sessionlebensdauer aktualisiert (in DB geschrieben)
    mysql_query("UPDATE `logins` SET lastActivity = ".time()." WHERE user = '".$_SESSION['user']."' LIMIT 1"); # Letzte Aktivität in DB speichern
PHP:
    # Letzte Aktivität des Users checken
    $LastActivityQ    = mysql_query("SELECT lastActivity FROM `logins` WHERE user = '".$_SESSION['user']."' LIMIT 1");
    $LastActivityR    = mysql_fetch_row($LastActivityQ);
$LastActivityR[0] wäre nun ein Timestamp.
So, letzte Aktivität mit time() vergleichen, 30 Min dazu addieren oder so ähnlich, stimmt's?
 
Zuletzt bearbeitet:
Werbung:
Es empfiehlt sich Daten auch als Daten und nicht als Timestamp abzuspeichern. Es gibt sowieso 2 Parts hier.
Der erste ist: Der User besucht eine Seite im eingeloggten zustand. Frag ab: ist Session['user'] gesetzt. Wenn ja soll er ein Update für den User an der Zeit machen.
Nun holst du dir alle Benutzer aus der Datenbank, deren letzte Aktivität länger als 30 min her ist und updatest deren loggedIn Status als false.
Ich bin jetzt kein SQL Profi und kann dir spontan nicht sagen, ob man das ganze Updaten von den Leuten in einem Query erledigen kann. Denke schon. Syntax könnte falsch sein aber ich denke so etwas:
Code:
UPDATE `login` SET `loggedIn` = 'false' WHERE `loggedIn` = 'true' AND TIMESTAMPDIFF(MINUTE, `lastActivity`, NOW()) >= 30;
Bin nicht sicher, aber es könnte funktionieren.
Dann brauchst du ingesamt nur die 2 Teile. ohne die hälfte in PHP machen zu müssen. Probier Datenbankspezifische Sachen auch der Datenbank zu überlassen.
Übrigens wird dein ausloggen mit der Session nicht funktionieren. Dafür muss der User ja eingeloggt sein. In der Variante die ich geschrieben hab prüft er direkt alle User. Das könnte man entweder bei jedem Seiten Aufruf prüfen oder durch einen Cronjob aufrufen lassen.
 
Du hast Recht.

So werden alle User gecheckt, anstatt nur der im Moment Eingeloggte. Sonst hätte ich es per CJ gemacht.

Danke dir.

Edit: So funktioniert's sogar. *.* Danke.
 
Zuletzt bearbeitet:
Neue Fragen + Problem

Okay, also Gilles:
Deine Idee ist ganz gut und das "automatische Ausloggen" funktioniert auch.

Aber ich habe ein Problem, welches anscheinend dieser Update Query verursacht.

Lasse ich diesen Query drin, werden tatsächlich alle ausgeloggt, die xx Minuten inaktiv waren.
Aber dazu muss man erstmal eingeloggt sein. Hier scheitert es. Das Einloggen funktioniert nicht, wenn die Query drin ist. Keine Fehlermeldung. Nichts. Nehme ich diesen Query raus, werde ich eingeloggt, aber das "automatische Ausloggen" funktioniert dann nicht mehr.

PHP:
<?php // Dieser Script wird in jede Datei includet, die geschützt werden soll

#####
$logoutTime = 5; # Automatischer Logout nach x Minuten Inaktivität
#####

session_start();
include_once('functions.php'); # Funktionen
dbConnect();

# Alle User, die online, aber länger als * Minuten inaktiv sind, ausloggen (Status ändern)
mysql_query("UPDATE `login` SET logged_in = 0 WHERE logged_in = 1 AND TIMESTAMPDIFF(MINUTE, `lastActivity`, NOW()) >= ".$logoutTime.""); # Dieser Query ist gemeint. Stimmt die Syntax nicht?!


# Login überprüfen
$checkQ = mysql_query("SELECT logged_in FROM `login` WHERE user = '".$_SESSION['user']."' LIMIT 1");
$checkR = mysql_fetch_array($checkQ);

    # prüft Sessionvariablen und ob die IP Adresse des Einloggers mit dem aktuellen User übereinstimmt (Session Hijacking vermeiden)
if(isset($_SESSION['user']) && $checkR['logged_in'] == 1 && $_SESSION['ip'] == md5(strrev($_SERVER['REMOTE_ADDR']))) {
    mysql_query("UPDATE `login` SET lastActivity = NOW() WHERE user = '".$_SESSION['user']."' LIMIT 1"); # Letzte Aktivität in DB speichern
} else logout(); # Login false


# ausloggen
if(isset($_GET['logout'])) logout();

# ansonsten, wenn also eingeloggt, alles in bester Ordnung und die Datei ist sichtbar.
?>
PHP:
# Alle User, die online, aber länger als * Minuten inaktiv sind, ausloggen (Status ändern)
mysql_query("UPDATE `login` SET logged_in = 0 WHERE logged_in = 1 AND TIMESTAMPDIFF(MINUTE, `lastActivity`, NOW()) >= ".$logoutTime.""); # Dieser Query ist gemeint. Stimmt die Syntax nicht?!
logout():
PHP:
# Logout
function logout() {
    mysql_query("UPDATE `login` SET logged_in = 0 WHERE user = '".$_SESSION['user']."' AND logged_in = 1");
    session_destroy();    
    session_unset();
    session_regenerate_id(true);
    
    header('Location: http://'.$_SERVER['SERVER_NAME'].'/admin/login');        # zur Loginseite weiterleiten
    exit;
}
Das Login-Script:
PHP:
    if(isset($_POST['user']) && !empty($_POST['user']) && isset($_POST['passwort']) && !empty($_POST['passwort'])) {    # wenn User und Passwort eingegeben und nicht leer sind
    
            $abfrage    = mysql_query("SELECT user, passwort FROM `login` WHERE user = '".$_POST['user']."' LIMIT 1");
            $row         = mysql_fetch_array($abfrage);
    
        if($_POST['user'] == $row['user'] && md5(strrev($_POST['passwort'].$xpw)) == $row['passwort']) {
            $_SESSION['user']        = $row['user'];
            $_SESSION['ip']            = md5(strrev($_SERVER['REMOTE_ADDR']));
            session_regenerate_id(true);    # neue Session-ID, um Session-Hijacking zu vermeiden
            
            $UpdateSQL = mysql_query("UPDATE `login` SET 
                lastLogin = NOW(),
                logged_in = 1,
                ip = '".$_SERVER['REMOTE_ADDR']."',
                UserAgent = '".$_SERVER['HTTP_USER_AGENT']."' 
                WHERE user = '".$_SESSION['user']."' LIMIT 1");    
 
            
            header('Location: http://'.$_SERVER['SERVER_NAME'].'/geheim');        # Weiterleiten
            exit;
Wenn ich diesen Query ausgebe, kommt "1" raus.

Anscheinend kommt kein Login zu Stande und ich werd zu der Loginmaske weitergeleitet.

Edit: Ich glaube, dass ich glaube, es wieder hingekriegt zu haben.
Beim Einloggen setze ich den logged_in Status auf 1 und lastLogin auf NOW();
Aber in der check.php Datei überprüfe ich ja mit dem oben markierten Query die letzte Aktivität, wenn dieser xx Minuten her ist, setze logged_in auf 0. Und das war beim Einloggen immer der Fall, weil hier lastActivity nicht aktualisiert wurde.
Ich bin dann zwar eingeloggt, aber werde gleich wieder ausgeloggt, weil beim Einloggen lastActivity nicht aktualisiert wurde.

Also es funktioniert bisher nun.
PHP:
            $UpdateSQL = mysql_query("UPDATE `login` SET 
                lastLogin = NOW(),
                logged_in = 1,
lastActivity = NOW(),
                ip = '".$_SERVER['REMOTE_ADDR']."',
                UserAgent = '".$_SERVER['HTTP_USER_AGENT']."' 
                WHERE user = '".$_SESSION['user']."' LIMIT 1");
 
Zuletzt bearbeitet:
Werbung:
ist euch eigentlich bewusst, dass ihr wirklich schlechten und vorallem unsicheren code publiziert?


$checkQ = mysql_query("SELECT logged_in FROM `login` WHERE user = '".$_SESSION['user']."' LIMIT 1");
wie in allen anderen querys ist eine sql injection möglich

... user = '".$_SESSION['user']."' L ...
... Agent = '".$_SERVER['HTTP_USER_AGENT']."' ...

hier ist eine header injection möglich, sehr geil bei firmenproxys....
header('Location: http://'.$_SERVER['SERVER_NAME'].'/geheim');

zudem reicht es nicht aus auf eine gültige session zu prüfen, was wenn die session von einem anderen webprojekt auf identischem server erzeugt wurde? sessions werden idr. im /tmp oder gespeichert und sind somit GLOBAL!

das Grundkonzept einen flag zu setzen ob der user angemeldet ist oder nicht ist auch selten schlecht, speicher einfach die letzte aktivität und prüfe dann ob diese in einem gewissen Zeitrahmen ist.

php - mysql ist wirklich veraltet - schaut euch bitte mal PDO oder MySqli an, mein Favorit ist und bleibt PDO. - Noch besser wäre natürlich auf Doctrine, Propel (mein Favorit) oder ähnliches umzusteigen.

Ihr seit nun alle 500+ Beiträge dabei, langsam solltet ihr euch mal mit OOP vertraut machen, dieses prozedurale rumgescripte ist wirklich nichts =)
 
PHP:
        # Gefahren in dem globalen Array Post entschärfen
        foreach ($_POST as $var => $value) {
            $value = trim ($value);
            $value = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
            $value = strip_tags ($value);
            $value = stripslashes ($value);
            $value = mysql_real_escape_string ($value);
            $_POST[$var] = $value;
        }
        # Gefahren in dem globalen Array Get entschärfen
        foreach ($_GET as $var => $value) {
            $value = trim ($value);
            $value = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
            $value = strip_tags ($value);
            $value = stripslashes ($value);
            $value = mysql_real_escape_string ($value);
            $_GET[$var] = $value;
        }
        # Gefahren in dem gloablen Array Cookie entschärfen
        foreach ($_COOKIE as $var => $value) {
            $value = trim ($value);
            $value = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
            $value = strip_tags ($value);
            $value = stripslashes ($value);
            $value = mysql_real_escape_string ($value);
            $_COOKIE[$var] = $value;
        }
        # Gloabalen Array Request Löschen, um Sicherheit zu erhöhen
        unset($_REQUEST);
        
        # Session
        foreach ($_SESSION as $var => $value) {
            $value = trim ($value);
            $value = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');    
            $value = strip_tags ($value);
            $value = stripslashes ($value);
            $value = mysql_real_escape_string ($value);
            $_COOKIE[$var] = $value;
        }

Reicht das nicht?
 
das ist auch extremst unsinnig.

lese am besten ein Buch oder etc. drüber oder informier dich im internet. Den code den du gepostet hast ist quatsch hoch 10.
 
Werbung:
ist euch eigentlich bewusst, dass ihr wirklich schlechten und vorallem unsicheren code publiziert?
...
Ihr seit nun alle 500+ Beiträge dabei, langsam solltet ihr euch mal mit OOP vertraut machen, dieses prozedurale rumgescripte ist wirklich nichts =)

Wo ist mein Code schlecht und wo ist er unsicher? Klar war das prüfen auf den Login nur auf die Session kein guter Schritt, jedoch sollte erst einmal eine vereinfachte Version des Projektes laufen (Prototyp).
All meinen Code schreibe ich objektorientiert und sicher. Nur ist es schlecht ein komplexes Problem auch sofort komplex lösen zu wollen. Das wird dann in kleinere Teile aufgesplittet. Seine erste Query habe ich ja auch bemängelt und habe eine allgemein gültige Query gepostet. Und was die Postings angeht: So hat nicht jeder mit vielen Postings viel Ahnung vom Fach. Es können viele Fragen gepostet worden sein, oder auch einiges im Off-Topic-Bereich ;)
 
Joa, ich poste ja auch nicht alles, damit es übersichtlich bleibt. Mit OOP und MySQLi fange ich erst an, wenn mein Loginsystem funktioniert, wie ich es will, sodass ich mir sicher bin, das Wesentliche verstanden zu haben.

Aber zum letzten Code:
Ich habe das irgendwo hier im Forum kopiert und wollte das Rad nicht neu erfinden.
Was ist daran aber unsinnig? So gehe ich alle Variablen durch ohne mir Gedanken machen zu müssen, dass eine vergessen wurde?!

Hier ist ja auch was Ähnliches:
Coder Wiki | HowTos | Alle $_POST Variablen escapen
 
Zuletzt bearbeitet:
ja, und jemand kopiert wieder deinen code und man muss ihm wieder erklären warum dies unsicher ist. es macht keinen sinn durch alle post variablen zu rennen und sie zu escapen. ganz im gegenteil - es geht enorm auf die performance. zudem verstösst man gegen grundprinzipien der OOP, - es ist nicht gekapselt, nicht testbar u.s.w.. Wäre Wäre es sinnvoll könnte man ja annehmen, dass PHP dies immer tun würde?

Es ist schon ein no-go auf eine Superglobale wie $_POST schreibend zu zu greifen, in erwachsenen Sprachen wie z.b. C# ist dies sogar völlig verboten.

@Gilles, ich habe keinen code von dir bemäkelt, dennoch sollte man, wenn man sowas sieht direkt drauf hinweisen und eine Weiterentwicklung stoppen. Es führt nur zu noch mehr Chaos und weiteren Sicherheitslücken.

Einfach mal ein Beispiel angucken:
PHP: PDO::prepare - Manual

bitte auch nochmal das Grundkonzept der OOP lesen: Objektorientierte Programmierung
Schaut euch auch mal das MVC Pattern an, ich empfehle jedem das "Blog tutorial" von CodeIgniter um das Grundprinzip halbwegs sauberer entwicklung zu verstehen.
 
Werbung:
Zurück
Oben