[PHP/MySQL] sicheres Sessionsystem?

Das hier ist erstmal ein grober Ansatz, wie du das ganze mit OOP realisieren könntest. Bei den Funktionen wo es dann ums Daten speichern geht, hatte ich keine Lust mehr, außerdem wusste ich nicht, wie ich das jetzt am besten realisiere (noch nie mit befasst). JSON scheidet aus, weils halt ne begrenzte Menge hat (oder du machst es "von Hand" und nicht mit den PHP Funktionen).
Wenn du allerdings Daten speicherst, hat in meinen Augen das Feld mit der User-ID keinen Sinn, das könnteste dann so bei den Daten abspeichern ;)
Das Daten speichern werden später so Sachen sein, wie aufgerufene Seite, etc....und das userid-feld ist einfach nur die Verbindung zur Userdatenbank, wenn ein User eben eingeloggt ist.

Werde mir die class heut nochmal komplett anschauen, danke....

Was mir aber noch eingefallen ist: Jemand Erfahrungen, ob ich das vielleicht mit nem IP-Check machen soll um Session-Klau vorzubeugen? Oder sonst irgendwie die Möglichkeit gegen Session-Klau vorzugehen?
 
OK, danke....wobei mir auch schonmal erklärt wurde, dass der check mit besonderen Zeichen irgendwie umgangen werden kann.
nicht, dass ich wüsste... auf jeden fall weitaus sicherer als addslashes...

Ja, derzeit läuft das über mysql_num_rows...aber ich blick grad nicht durch wie du es jetzt meinst? Denn im ersten satz sagst du, dass count() besser ist. Dann aber schreibst du, dass ich es so lassen soll wenn es count() nutzt und dann auf einmal dann mysql_num_rows würde ich nur eine Abfrage brauchen statt wie jetzt 2...aber jetzt sind es doch 2 und die laufen über mysql_num_rows
ja, also in deinem speziellen fall wäre es performanter, mysql_num_rows zu machen, weil du dann nur eine query machen musst... ABER du nutzt die datenbankklasse ja ncoh an vielen anderen stellen im script, deswegen wäre es ratsamer, COUNT() zu nutzen. das ist zwar in diesem fall jetzt etwas langsamer (im millisekundenbereich), aber insgesamt wird dein script performanter laufen, weil du an vielen weiteren stellen im script sicherlich einträge zählen musst, ohne, dass du die daten der einträge benötigst.


Was mir aber noch eingefallen ist: Jemand Erfahrungen, ob ich das vielleicht mit nem IP-Check machen soll um Session-Klau vorzubeugen? Oder sonst irgendwie die Möglichkeit gegen Session-Klau vorzugehen?
ein browser-check ist nie verkehrt... ein ip-check macht die ganze sache zwar sicherer, aber dadurch sinkt die benutzerfreundlichkeit. kommt sicherlich auch darauf an, was du programmierst... wenn du ein startseitenscript wie klamm planst, wäre ein ip-check sicherlich fehl am platz... kein user möchte sich ständig neu einloggen müssen, um ein popup zu bestätigen... bei einem browsergame würde ich wiederum zum ip-check raten.
 
ein browser-check ist nie verkehrt... ein ip-check macht die ganze sache zwar sicherer, aber dadurch sinkt die benutzerfreundlichkeit. kommt sicherlich auch darauf an, was du programmierst... wenn du ein startseitenscript wie klamm planst, wäre ein ip-check sicherlich fehl am platz... kein user möchte sich ständig neu einloggen müssen, um ein popup zu bestätigen... bei einem browsergame würde ich wiederum zum ip-check raten.

Was ich halt als Problem sehe ist, dass Besucher mit so wechselnden IP`s kommen und damit dieser Besucher ja immer ein neue Session zugeordnet wird, wenn ich beim abfragen der session-id in der DB die ip überpüfe, die aber dann ja eine andere ist.
Gibts denn irgendwie ne andere Variable, die auf jedenfall von jedem Browser immer übermittelt wird?
Die Verwendung ist unterschiedlich. Also es soll für vieles verwendet werden können, da ich versuche mir ne Basis zu schreiben, auf der ich dann immer Scripts drauf entwickeln kann ohne immer Loginsystem, etc. neu zu schreiben.
 
Der User Agent steht z.B. in $_SERVER['HTTP_USER_AGENT'] ;)

Wird das immer übermittelt und kann das auch irgendwie bei einem User sich immer ändern...bzw. welche Daten werden denn immer übermittelt, die ich mit speichern kann und dann eben um Session-Klau zu verhindern bei der anzahl()-Abfage einfach noch ein where daten = '$daten' and daten2 = '$daten2'....hinzufügen kann.
 
Natürlich ist auch der User-Agent manipulierbar und sollte mit den selben Sicherheitsmaßnahmen bedacht werden wie alle anderen vom Nutzer kommenden Daten auch. Zuverlässig ist die Angabe also nicht.

Ich verstehe im Übrigen nicht, warum Leute ihr eigenes Sessionsystem schreiben. Welchen Vorteil hat das in Bezug zum bereits in PHP vorhandenen?
 
Natürlich ist auch der User-Agent manipulierbar und sollte mit den selben Sicherheitsmaßnahmen bedacht werden wie alle anderen vom Nutzer kommenden Daten auch. Zuverlässig ist die Angabe also nicht.
natürlich ist er das und natürlich macht ihn das nicht 100 prozentig zuverlässig. wenn der angreifer zb den gleichen browser (+gleiches betriebssystem) benutzt wie das opfer, ist der schutz umgangen. allerdings weiß der angreifer im normalfall nicht, welcher browser vom opfer genutzt wird.

Ich verstehe im Übrigen nicht, warum Leute ihr eigenes Sessionsystem schreiben. Welchen Vorteil hat das in Bezug zum bereits in PHP vorhandenen?
bessere performance und mehr sicherheit.
 
natürlich ist er das und natürlich macht ihn das nicht 100 prozentig zuverlässig. wenn der angreifer zb den gleichen browser (+gleiches betriebssystem) benutzt wie das opfer, ist der schutz umgangen. allerdings weiß der angreifer im normalfall nicht, welcher browser vom opfer genutzt wird.
Genau das meine ich...deswegen eben die Frage, was man da noch alles nutzen kann, was auf jedenfall fest ist und sich eben nicht ändern kann, wie es bei der ip ist.
bessere performance und mehr sicherheit.

dito und ich schaff es damit eben auch so Sachen wie "Wer ist wo"..."Wer liest dieses Themao"...etc.
 
Für deine genannten Funktionen kannst du auch einfach session_set_save_handler mit einer DB als Backend nutzen, fertig. Die Sicherheit kannst du auch da mit reinbringen und Performance ist gleich.
Was mich nur jedesmal nervt, jeder meint sein eigenes Süppchen zu kochen, auch gerade bei Logins, es gibt ja nicht umsonst den Standard der Sessions und nicht umsonst die Erweiterung die Sessionsspeicherung selbst zu lösen.
Sowas ruft bei mir einfach nur Unverständnis auf, wieder zig Zeilen selbst gecodet, die PHP schon kann, und sollte mal jemand anders mit dem Script arbeiten müssen, muss er sich wieder in den ganzen proprietären Mist einarbeiten.
Aber es bleibt ja nicht bei einem solchen System, dass man dann lernen muss, das ist dann ja wieder pro Kunde wieder ein neues System.
 
Genau das meine ich...deswegen eben die Frage, was man da noch alles nutzen kann, was auf jedenfall fest ist und sich eben nicht ändern kann, wie es bei der ip ist.
soweit ich weiß gibt es da nur die ip

dito und ich schaff es damit eben auch so Sachen wie "Wer ist wo"..."Wer liest dieses Themao"...etc.
das geht auch ohne eigenem session-system.

an sich ist es geschmackssache, was man nutzt (php-sessions oder eigene). beides hat seine vor- und nachteile.

wenn du die php-sessions in der datenbank speicherst, wie ice-breaker meinte, sollte auch das problem des möglichen auslesens der session bei shared webhosting-angeboten gelöst sein.
 
soweit ich weiß gibt es da nur die ip
JA, aber die kann sich ja bei Besuchern ändern, die eben solche Sicherheitsprogramme nutzen und dabei wird ja ein einloggter User immer automatisch ausgeloggt, da die Sessionid in der DAtenbank ja auf Grund der anderen IP nichtmehr geladen werden kann.
das geht auch ohne eigenem session-system.

an sich ist es geschmackssache, was man nutzt (php-sessions oder eigene). beides hat seine vor- und nachteile.

wenn du die php-sessions in der datenbank speicherst, wie ice-breaker meinte, sollte auch das problem des möglichen auslesens der session bei shared webhosting-angeboten gelöst sein.

Naja was wäre denn der Vorteil und der NAchteil von dem php-session-system? Hab schon versucht da was zu zu finden, aber nicht wirklich was gefunden?
 
So, also hab das ganze jetzt nochmal in ner Class umgesetzt, allerdings noch zwei Fragen:

1. Wie kann ich meine $db-Klasse da richtig drin verwenden?
2. Wie schaffe ich es die Variable $dbpraefix da zu laden, damit die verwendet werden kann?

Hier die Class:
PHP:
<?php
class session{

	function sessionload() { //Löscht alle alten Sessions und überprüft auf Session
		$checksestime = time() - (60 * 60 * 2); //timestamp von jetzt - 2 Stunden erstellen 
		$checklogtime = time() - (60 * 20); //timestamp von jetzt - 20 Minuten erstellen 
		$db->query("delete from ".$dbpraefix."_sessions where lastactivity < '$checksestime' and userid='0'");//Lösche alle Sessions bei denen kein User eingeloggt ist und letzte Aktivität länger als 2 Stunden her ist 
		$db->query("delete from ".$dbpraefix."_sessions where lastactivity < '$checklogtime' and userid!='0' and locked = '0'");//Lösche alle Sessions bei denen ein User eingeloggt ist, letzte Aktivität länger als 20 Minuten her ist und "Eingeloggt bleiben" nicht aktiviert ist 

		if(isset($_COOKIE['sessionid'])){
        $_COOKIE['sessionid'] = mysql_real_escape_string($_COOKIE['sessionid']);
		}else{
        $_COOKIE['sessionid'] = '';
		}
        $sessionid = $_COOKIE['sessionid'];
		if($sessionid != ""){//Daten gefunden 
			$sessionanzahl = $db->anzahl("Select * from ".$dbpraefix."_sessions where sessionid = '$sessionid'");//Anzahl der Datenbankeinträge für $sessionid 
			if($sessionanzahl != 1){
				$sessionid = "";//Lösche Session-Variable 
			} 
		} 

		if($sessionid == ""){//Keine Session vorhanden oder Session gelöscht 
			$this->startsession();
		}
		return $sessionid;
	}
	
	function startsession() { //Startet eine neue Session
		$sessionid = md5(uniq_id('sessions', true));//einzigartige ID erstellen 
		$db->query("insert into ".$dbpraefix."_sessions set sessionid = '$sessionid',lastactivity=".time().",user='0',locked='0'"); 
		setCookie("sessionid", $sessionid, time() + 60 * 60 * 24 * 356 * 10);//Cookie für 10 Jahre speichern (sollte ja hoffentlich reichen) 
		return $sessionid;
	}
	
	function loadsession($sessionid) { //Lädt die Date der Session
		$session = $db->data("Select * from ".$dbpraefix."_sessions where sessionid = '$sessionid'");//Frage Daten der Session ab 
		$db->query("update ".$dbpraefix."_sessions set lastactivity = ".time()." where sessionid = '$sessionid'");//Update lastactivity-time 
		return $session;//Gibt das Array zurück mit den Daten
	}
	
	function login($userid, $lock=false){
		if($lock != 1){$lock = 0;}
		$db->query("update ".$dbpraefix."_sessions set userid='$userid',locked='$lock' where sessionid = '$sessionid'");//Setze Userid in die session ein 
    }
	
	function logout($sessionid){
		$db->query("update ".$dbpraefix."_sessions set userid='0',locked='0' where sessionid = '$sessionid'");//Lösche Userid und Locked (egal ob "Eingeloggt bleiben" aktiviert war oder nicht 
    }
}
?>

Daraufhin lade ich auf der Startseite dann folgendes direkt am Anfang:

PHP:
include "class.session.php"; 
$session = new session(); //Sessionklasse starten
$sessionid = $session->sessionload();//Sessionid wird geladen
$userdata = $session->loadsession($sessionid);//Fragt die Daten über die Session ab und gibt die Infos über $userdata[wert] zurück

Beim login wird dann über $session->login($userid,$locked); gestartet und beim logout eben $session->logout($sessionid);

Was haltet ihr von und passt das so?
 
Zuletzt bearbeitet:
Schon beim erstenmal drüberschauen fallen soviele Probleme/Fehler auf das ich mir die gar nicht alle merken kann. Teste einfach mal :ugly:
 
Wenn Du ein Datenbankobject brauchst, übergib es doch im Konstruktor. Einen sinnvolleren Platz gibt es in dieser Umgebung nicht...
 
Viele wege führen nach Rom. Z.B. durch Vererbung, durch übergabe einer DB Instanz, mittels Singelton Pattern, mit global oder...

$dbpraefix... ist der überhaupt nötig? Ansonsten gehört das eigentlich zur DB Klasse. Also speicher den Prefix in der Datenbankklasse und ruf ihn darüber auf. Alternativ kannst du auch mit einer konstante Arbeiten, passt aber in der Form dann nicht zu OOP.

Und noch ein tip wie der Aufruf der Session Klasse passieren sollte:
PHP:
include "class.session.php"; 
$session = new session();

Im Konstruker der Klasse sollte entschieden werden ob eine neue Session erzeugt wird oder eine bestehende geladen. Das was du da zurzeit machst ist quatsch... das ist umständlich hoch 10 und damit auch fehler anfällig und das ist nicht der sinn von OOP.
 
Viele wege führen nach Rom. Z.B. durch Vererbung, durch übergabe einer DB Instanz, mittels Singelton Pattern, mit global oder...

$dbpraefix... ist der überhaupt nötig? Ansonsten gehört das eigentlich zur DB Klasse. Also speicher den Prefix in der Datenbankklasse und ruf ihn darüber auf. Alternativ kannst du auch mit einer konstante Arbeiten, passt aber in der Form dann nicht zu OOP.

Und noch ein tip wie der Aufruf der Session Klasse passieren sollte:
PHP:
include "class.session.php"; 
$session = new session();

Im Konstruker der Klasse sollte entschieden werden ob eine neue Session erzeugt wird oder eine bestehende geladen. Das was du da zurzeit machst ist quatsch... das ist umständlich hoch 10 und damit auch fehler anfällig und das ist nicht der sinn von OOP.

Hab es schon mit "global $db,$dbpraefix;" probiert, aber damit gehts nicht so einfach...wie würdest du es denn anders aufrufen? Also könntest vielleicht bisschen näher erklären oder einfach mal an meinem Beispiel zeigen, wie du es meinst?
 
Was heißt mit global gehts nicht so einfach? Das geht schon mit global, zwar sehr unschön da es gegen die Prinzipien von OOP verstößt, aber vorerst egal.

Und wie ich das meine hab ich schon gepostet.

Das:

PHP:
include "class.session.php"; 
$session = new session(); //Sessionklasse starten
$sessionid = $session->sessionload();//Sessionid wird geladen
$userdata = $session->loadsession($sessionid);

könnte IMO auch so aussehen:

PHP:
include "class.session.php"; 
$session = new session();
 
Was heißt mit global gehts nicht so einfach? Das geht schon mit global, zwar sehr unschön da es gegen die Prinzipien von OOP verstößt, aber vorerst egal.

Und wie ich das meine hab ich schon gepostet.

Das:

PHP:
include "class.session.php"; 
$session = new session(); //Sessionklasse starten
$sessionid = $session->sessionload();//Sessionid wird geladen
$userdata = $session->loadsession($sessionid);

könnte IMO auch so aussehen:

PHP:
include "class.session.php"; 
$session = new session();

Du meinst also, dass über $session[...] dann die Daten zurückgegeben werden? Aber dann müsste ich ja ne Art default-Wert machen wenn session() aufgerufen wird, oder? Denn dann könnte ich es in der class ja so machen, dass ich die funktionen so verbinde, dass am Ende auf jedenfall die Session-Daten ausgelesen werden und zurückgegeben werden. Aber wie lege ich denn den default-Wert fest? Denn müsste ja im Prinzip dann sessionload() aufrufen zu Beginn, von der aus das dann alles weitergeleitet wird.