# dauerhafter Login / Cookie oder Session Lifetime?



## versuch13 (21. Januar 2008)

Ich möchte einen dauerhaften Login (7 Tage) realisieren. Nun frage ich mich was die beste und vor allem sicherste Methode dafür ist? 

Momentan werden eingeloggte User an einer Session erkannt. Daher habe setze ich nun beim Login einen Cookie, besucht der User die Seite und es ist ein Cookie gestetzt aber keine Session so wird diese gestaret.

Session Einstellungen

```
ini_set('session.use_trans_sid', 0);
    ini_set('session.use_cookies', 1);
```

Beim einloggen:

zu erste Datenbankabfrage und vergleich der Formulardaten mit den Daten der Datenbank und dann werden Sessions und Cookies gesetzt.


```
session_regenerate_id(true);
                $_SESSION['logged_in'] = true;
                $_SESSION['user'] = fct_text($row['name']);
                $_SESSION['userid'] = (int) $row['id'];
                $_SESSION['rights'] = (int) $row['rights'];
                $sessionid = session_id();
                $query =     "INSERT INTO sessions (uid, sessionid, savetime) VALUES (".$row['id'].", '".$sessionid."', NOW())
                            ON DUPLICATE KEY UPDATE savetime = NOW(), sessionid = '".$sessionid."'
                            ";        
                $result = mysql_query($query) OR die(mysql_error());
                setcookie('UID', (int) $row['id'], time()+3600*24*7);
                setcookie('SID', $sessionid, time()+3600*24*7);
```

Kommt der User nun wieder und es besteht ein Cookie:

```
if(isset($_COOKIE['SID']) AND !isset($_SESSION['logged_in'])) {
        $sql =    "SELECT
                    a.`id`,
                    a.`name`,
                    a.`rights`,
                    b.`sessionid`
                FROM
                    `user` as `a`
                INNER JOIN
                    `sessions` as `b`
                ON 
                    a.`id` = b.`uid`
                WHERE
                    a.`id` = ".(int) $_COOKIE['UID']."
                    AND DATEDIFF(NOW(), b.`savetime`) <= 7
                ";
        $result = mysql_query($sql) OR die(mysql_error());
        $row = mysql_fetch_assoc($result);
        if($row['sessionid'] == $_COOKIE['SID']) {
            $_SESSION['logged_in'] = true;
            $_SESSION['user'] = fct_text($row['name']);
            $_SESSION['userid'] = (int) $row['id'];
            $_SESSION['rights'] = $row['rights'];         
        }
    }
```

ich habe mir gedacht ich speicher zusätzlich etwas in der Datenbank um den User nochmals zu identifizieren, ich speichere die SessionID beim einloggen in der Datenbank und in einem dauerhaften Cookie und vergleiche diese Daten beim erneuten setzen der Session. Macht dass so überhaupt Sinn? Eher nicht oder? Denn gelangt jemand an die Cookie Daten so erhält er zutritt. 

Des weiteren, ich habe gesehen dass das Loginsystem von Drupal mit session.cookie_lifetime die Session Dauer auf knapp vier Wochen setzt, aber auch dort werden zusätzliche Daten in der Datenbank abgelegt nur ganz durchsteigen tue ich da nicht. Wäre session.cookie_lifetime zu erhöhen auch eine Möglichkeit? 

Worauf ich also hinaus will ist hoffentlich klar, wie sichere ich das System ab?


----------



## versuch13 (21. Januar 2008)

Das Thema ist weit verbreitet, bevor ich das Thema eröffnet habe habe ich auch hier schon einige Themen gefunden die sich damti befassen und auch reichlich im Netz recherchiert, aber eine zufriedenstellende Lösung konnte ich einfach nicht finden. 

Ist das ein so schweres Thema? Wie ist es wenn jemand die Cookie Daten in die Finger bkeommt, kann man dann überhaupt irgendwie verhindern dass sich die Person einen fremden Account vornimmt?


----------



## Gumbo (21. Januar 2008)

Die Lebenszeit des Sitzungscookies zu verlängern halte ich nur dann für sinnvoll wenn auch gleichzeitig die Lebenszeit der Sitzung selbst, also der serverseitig gespeicherten Daten, verlängert wird. Doch das wäre keine gute Idee, da so schnell der Speicherplatz von möglicherweise gar nicht mehr benötigten Sitzungsdaten aufgefressen würde.
Besser, finde ich, ist es da neben dem Sitzungscookie einen weiteren Cookie einzusetzen, mit dem die Identifizierung des Benutzers durchgeführt wird. Als Wert schlage ich die Benutzer-ID sowie ein paar weitere Informationen über den Benutzer (beispielsweise digitaler Fingerabdruck) in verschlüsselter Form vor.
Alternativ zur Verschlüsselung kannst du auch ein Cookie mit den Werten und einen zusätzlichen Cookie zur Authentifizierung des Cookies mit den Werten einsetzen.


----------



## versuch13 (21. Januar 2008)

Gumbo hat gesagt.:


> Die Lebenszeit des Sitzungscookies zu verlängern halte ich nur dann für sinnvoll wenn auch gleichzeitig die Lebenszeit der Sitzung selbst, also der serverseitig gespeicherten Daten, verlängert wird. Doch das wäre keine gute Idee, da so schnell der Speicherplatz von möglicherweise gar nicht mehr benötigten Sitzungsdaten aufgefressen würde.



Das habe ich schon vermutet, ok, danke. Aber dazu trotzdem auch noch eine kurze Frage. Wenn man die Lebenszeit des Sessioncookies auf sagen wir mal 24 Std. setzen würde, was zum Beispiel Sinn machen würde bei einer Seite welche täglich meist die selben Nutzer hat, so würde für die User die täglich vorbei kommen der Login dauerhaft erhalten bleiben und wenn man die SessionId bei jedem Seitenaufruf erneuert dann wäre das doch eine ziemliche sichere Methode einen dauerhaften Login zu realisieren oder? Würde denn bei einer so kurzen Lebenszeit der Server auch stark belastet werden oder könnte man diese Möglichkeit in Erwägung ziehen? Und bleiben die Session Variablen auch in jedem Fall über 24 Stunden erhalten?



Gumbo hat gesagt.:


> Alternativ zur Verschlüsselung kannst du auch ein Cookie mit den Werten und einen zusätzlichen Cookie zur Authentifizierung des Cookies mit den Werten einsetzen.



Das verstehe ich leider nicht, vllt kannst du darauf nochmal eingehen bitte?



Gumbo hat gesagt.:


> Besser, finde ich, ist es da neben dem Sitzungscookie einen weiteren Cookie einzusetzen, mit dem die Identifizierung des Benutzers durchgeführt wird. Als Wert schlage ich die Benutzer-ID sowie ein paar weitere Informationen über den Benutzer (beispielsweise digitaler Fingerabdruck) in verschlüsselter Form vor.



In etwa so sieht das nun auch aus. 

Beim absenden des Login Formulares.

```
$sql =     "SELECT
                        `id`, `name`, `password`, `rights`
                    FROM 
                        `user` 
                    WHERE
                        `name` = '". mysql_real_escape_string($_POST['user']) ."' AND `password` = '". mysql_real_escape_string(md5($_POST['password'])) ."' AND `flag` = 1 
                    ";
                            
            $result = mysql_query($sql) OR die(mysql_error());
                    
            if( !mysql_num_rows($result) ) {
                $msg .= "Login fehlgeschlagen. Ein Benutzer mit diesen Daten ist nicht vorhanden.<br />";
                $info .= 'Hast du deinen Usernamen oder Passwort vergeßen? Beantrage hier neue Zugangsdaten.';
            } else {
                $row = mysql_fetch_array($result);
                session_regenerate_id(true);
                $_SESSION['logged_in'] = true;
                $_SESSION['user'] = fct_text($row['name']);
                $_SESSION['userid'] = (int) $row['id'];
                $_SESSION['rights'] = (int) $row['rights'];
                $sessionid = session_id();
                $cookieLifetime = time()+3600*24*7;
                $hash = md5(session_id().$_SERVER['HTTP_USER_AGENT']);
                $query =     "INSERT INTO sessions (uid, sessionid, savetime) VALUES (".$row['id'].", '".$sessionid."', NOW())
                            ON DUPLICATE KEY UPDATE savetime = NOW(), sessionid = '".$sessionid."'
                            ";        
                $result = mysql_query($query) OR die(mysql_error());
                setcookie('UID', $row['id'], $cookieLifetime);
                setcookie('SID', $hash, $cookieLifetime);
            }
```
Beim widerkehrenden Nutzer mit gesetzten Cookies:

```
if(isset($_COOKIE['SID']) AND !isset($_SESSION['logged_in'])) {
    
        $sql =    "SELECT
                    a.`id`,
                    a.`name`,
                    a.`rights`,
                    b.`sessionid`
                FROM
                    `user` as `a`
                INNER JOIN
                    `sessions` as `b`
                ON 
                    a.`id` = b.`uid`
                WHERE
                    b.`uid` = ".(int) $_COOKIE['UID']."
                    AND DATEDIFF(NOW(), b.`savetime`) <= 7
                    AND a.`flag` = 1
                ";
        $result = mysql_query($sql) OR die(mysql_error());
        $row = mysql_fetch_assoc($result);
        if(md5($row['sessionid'].$_SERVER['HTTP_USER_AGENT']) == $_COOKIE['SID']) {
            $_SESSION['logged_in'] = true;
            $_SESSION['user'] = fct_text($row['name']);
            $_SESSION['userid'] = (int) $row['id'];
            $_SESSION['rights'] = $row['rights'];
        }
        
    }
```

Ich speichere also die reine Session Id in der Datenbank, und einen Cookie der aus der SessionId und dem HTTP_USER_AGENT in codierter Form besteht und vergleiche dann beim widerkehrenden Nutzer die SessionId aus der DB + HTTP_USER_AGENT in codierter Form mit dem Cookie. Durch die Verwendung des HTTP_USER_AGENT ergibt sich in meinen Augen ein kleiner Pluspunkt sollten Cookie Daten in fremde Hände kommen. Aber wenn jemand an die Cookie Daten ran käme, dann wäre es trotzdem nicht wirklich ganz sicher. 

Ich achte schon sehr stark darauf alle XSS Lücken zu schließen und denke von der Seite aus ist auch alles soweit sicher, aber man kann ja immer mal eine Kleinigkeit übersehen und das größte Problem für mich liegt nur darin dass ich nicht weiß welche  weiteren/ob überhaupt weitere Möglichkeiten bestehen wie jemand an die Cookie Daten kommen könnte. Klar, wenn jemand seine Cookie Daten selbst veröffentlicht, aber wenn theoretisch alle XSS Lücken geschlossen sind, besteht dann überhaupt noch Grund zur Sorge? 

Vielen Dank und Grüße


----------



## versuch13 (23. Januar 2008)

Kann mir vielleicht noch jemand die Fragen aus meinem letzten Post beantworten? Ich suche mich dumm und dämlich und finde irgendwie nichts anständiges zu dem Thema. Aber es gibt so viele Webseiten die einen dauerhaften Login ermöglichen, es kann doch nicht sein dass dort überall die Sicherheit vernachlässigt wird oder? Vielen Dank, Grüße


----------



## Chaosengel_Gabriel (24. Januar 2008)

So in der Art hab ich das...
Zusätzlich wird IP gesichert, sicher is sicher... ^^


```
// Prüfen, ob ein Autologin des Users stattfinden muss
if(isset($_COOKIE['Autologin']) AND !isset($_SESSION['UserID'])){
$sql = "SELECT
ID
FROM
User
WHERE
Autologin = '".mysql_real_escape_string($_COOKIE['Autologin'])."'
";
$result = mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
$row = mysql_fetch_assoc($result);
if(mysql_num_rows($result) == 1)
doLogin($row['ID'], '1');
}

// Online Status der User aktualisieren
if(isset($_SESSION['UserID'])){
$sql = "UPDATE
User
SET
Letzte_Aktion = '".time()."'
WHERE
ID = '".$_SESSION['UserID']."'
";
mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
}

// User ohne Autologin ausloggen
$sql = "UPDATE
User
SET
SessionID = NULL,
Autologin = NULL,
IP = NULL
WHERE
'".(time()-(60*30))."' > Letzte_Aktion AND
Autologin IS NULL
";
mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());

// Kontrollieren, ob ein automatisch ausgeloggter User noch eine gültige Session besitzt
if(isset($_SESSION['UserID'])){
$sql = "SELECT
SessionID
FROM
User
WHERE
ID = '".$_SESSION['UserID']."'
";
$result = mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
$row = mysql_fetch_assoc($result);
if(!$row['SessionID']){
$_SESSION = array();
session_destroy();
}
}
```


----------



## versuch13 (24. Januar 2008)

Und was enthält $_COOKIE['Autologin']? 

Aber auch hier, bekommt ein wer den Cookie in die Hand so kann er sich 
ohne weiteres einloggen oder nicht? Da bin ich mit dem vergleich des 
UserAgents noch mehr auf der sicheren Seite oder?


----------



## Chaosengel_Gabriel (24. Januar 2008)

Der Cookie wird bei login gesetzt...

```
// Falls der Nickname und das Passwort übereinstimmen..
$sql = "SELECT
ID
FROM
User
WHERE
Nickname = '".mysql_real_escape_string(trim($_POST['Nickname']))."' AND
Passwort = '".md5(trim($_POST['Passwort']))."'
";
$result = mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
// wird die ID des Users geholt und der User damit eingeloggt
$row = mysql_fetch_assoc($result);
// Prüft, ob wirklich genau ein Datensatz gefunden wurde
if (mysql_num_rows($result)==1){
doLogin($row['ID'], isset($_POST['Autologin']));
}
////Die Login Funktion
// Loggt einen User ein, ..
function doLogin($ID, $Autologin=false)
{
// .. indem die aktuelle Session ID in der Datenbank gespeichert wird
$sql = "UPDATE
User
SET
SessionID = '".mysql_real_escape_string(session_id())."',
Autologin = NULL,
IP = '".$_SERVER['REMOTE_ADDR']."',
Letzte_Aktion = '".mysql_real_escape_string(time())."',
Letzter_Login = '".mysql_real_escape_string(time())."'
WHERE
ID = '".$ID."'
";
mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
// Wenn 'eingeloggt bleiben' aktiviert wurde
if($Autologin){
// Zufallscode erzeugen
$part_one = substr(time()-rand(100, 100000),5,10);
$part_two = substr(time()-rand(100, 100000),-5);
$Login_ID = md5($part_one.$part_two);
// Code im Cookie speichern, 10 Jahre dürfte genügen
setcookie("Autologin", $Login_ID, time()+60*60*24*365*10);
$sql = "UPDATE
User
SET
Autologin = '".$Login_ID."'
WHERE
ID = '".$ID."'
";
mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());
}
function getRights()
{
$rights = array();
// .. indem die Rechte eines User aus der Datenbank ausgewählt werden..
if(isset($_SESSION['UserID'])){
$sql = "SELECT
Recht
FROM
User_Rechte
WHERE
UserID = '".$_SESSION['UserID']."'
";
$result = mysql_query($sql) OR die ("<pre>\n".$sql."</pre>\n".mysql_error());
// .. und als array zurückgegeben werden
while($row = mysql_fetch_assoc($result))
$rights[] = $row['Recht'];
}
return $rights;
}
// Daten des Users in der Session speichern
$sql = "SELECT
Nickname
FROM
User
WHERE
ID = '".$ID."'
";
$result = mysql_query($sql) OR die("<pre>\n".$sql."</pre>\n".mysql_error());

$row = mysql_fetch_assoc($result);
$_SESSION['UserID'] = $ID;
$_SESSION['Nickname'] = $row['Nickname'];
// Rechte in der Session speichern
$_SESSION['Rechte'] = getRights();
}
```

Überprüfen und abfragen zum sicher gehen kannste theretisch alle erreichbaren User-Infos...
Bleibt ja jedem selbst überlassen, wie genau er sein will...

Mit bestimmter IP hält der maximal 24Std...
Dann musste die aktualisieren, indem du eine weitere Variable beim User hast, der ihn Identifiziert, also den Cookie...


----------



## versuch13 (24. Januar 2008)

Du identifizierst den User also nur anhand er IP Adresse? Das ist eigentlich keine gute Idee oder sehe ich das falsch? Denn es ist möglich dass mehrere User die selbe IP Adresse hätten, oder dass ihre IP Adresse von Request zu Request verändert wird.


----------



## Chaosengel_Gabriel (24. Januar 2008)

Das Hauptsächliche ist der Cookie, da alle anderen Daten vom User sich ändern können...


----------



## versuch13 (29. Januar 2008)

Hat sonst noch jemand vielleicht eine/n Idee/Ratschlag?


----------



## PanchoS (9. Dezember 2008)

Nun ist der Thread zwar schon eine ganze Weile alt, aber hier ist eine Auseinandersetzung mit dem Thema, die ich für außerordentlich gut erachte: http://jaspan.com/improved_persistent_login_cookie_best_practice

Viele Grüße, Pancho


----------



## splasch (9. Dezember 2008)

Naja die Token Methode gibt auch net viel Schutz sie verhindert leglich das sich 2 User zur selben Zeit einlogen können.

Wenn aber der Angreiffer das letzte Aktuelle cookie ausliest und der eigentlicher User ist  danach offline. So hätte der Angreiffer dann Zugang so lang eben bis der eigentliche User wieder online geht.

Der eigentlich User würde dann feststellen das er nicht mehr eingelogt ist und müsse sich neu Einlogen. Wenn das bassiert wurde er damit den Angreifer rauswerfen. Wenn der eh net bis dahin schon das Pw geändert hat.

Das ist  ähnlich so wie bei den Multiacount diese zu entarnen ist schwierieg.

Grundregel gilt je mehr du Prüft um so sicherer wird das ganze werden.

Mögliche Maßnahmen die mir spontan dazu mal einfallen:

1.) Token Methode  speichern in Db und cookie
2.) Betriebsystem check version und  nummer  unsw. speichern in Db bei Autologin prüfen
3.) Browser check type version unsw in Db Speichern bei Autologin prüfen
4.) IP check fraglich bei fixen IP were das Möglich am besten user auswählen lassen

Mfg Splasch


----------

