PHP - $_SESSION verändert sich aufeinmal
Patrick Hartwig
- php
0 Felix Riesterer
0 Patrick Hartwig
0 dedlfix
0 Jonny 5
Hallo,
Ich habe einen alten Code von mir einmal ausgegraben (ich weiß, ist nicht sonderlich gut programmiert) und bin dort gerade gerade auf der Fehlersuche:
// Erst auf Änderungen über POST überprüfen
if(isset($_POST['date']) and is_numeric($_POST['date'])) {
// Wenn ein Eintrag gelöscht wird
$day = $_POST['date'];
mysql_query("DELETE FROM calender WHERE day = '$day' AND month = '$month' AND year = '$year'");
}
elseif(isset($_POST['date2']) and isset($_POST['name']) and !empty($_POST['name'])) {
echo "<br><br>";
// Wenn ein neuer Eintrag geschrieben wird
$name = htmlentities($_POST['name'], ENT_QUOTES);
$date = $_POST['date2'];
$date = explode(";",$date);
$inputday = $date[0];
$inputmonth = $date[1];
$inputyear = $date[2];
mysql_query("INSERT INTO calender (day,month,year,name) VALUES ('$inputday','$inputmonth','$inputyear','$name')");
}
// Daten des Calenders aus der Datenbank holen
$result = mysql_query("SELECT users FROM permissions WHERE permission = 'calender'");
while($row = mysql_fetch_assoc($result)) {
$users = explode(";",$row['users']);
}
$result = mysql_query("SELECT day,name FROM calender WHERE month = '$month' AND year = '$year'");
$dates = array();
$db_days = array();
$db_names = array();
while($row = mysql_fetch_assoc($result)) {
array_push($db_days,$row['day']);
array_push($db_names,$row['name']);
}
$dates["day"] = $db_days;
$dates["name"] = $db_names;
// Kalenderanzeige
echo "<table id='calender'>";
echo "<tr><td>Montag</td><td>Dienstag</td><td>Mittwoch</td><td>Donnerstag</td><td>Freitag</td><td>Samstag</td><td>Sonntag</td></tr>";
while($finished == false) {
echo "<tr>";
for($i=0;$i<7;$i++) {
// Gibt eine neue Wochenzeile aus
if($started == true) {
// Wenn die Monatsausgabe angefangen hat
if($k > 0) {
// Wenn noch Monatstage auszugeben sind
$k -= 1;
$current = $k_old - $k;
$position = array_search($current,$dates["day"]);
if($position !== false) {
// Wenn was auf diesem Feld eingetragen wurde
if(isset($_SESSION['name']) and in_array($_SESSION['name'],$users)) {
// Eingeloggt und Berechtigung zum ändern
echo '<form action="index.php?s=calender" method="post">';
echo "<td>" . $current . "<br>" . $dates["name"][$position] . "<br><input type=\"hidden\" name=\"date\" value=\"$current\"/><input type=\"submit\" value=\"Löschen\"/></td>";
echo '</form>';
}
elseif(isset($_SESSION['name']) and !in_array($_SESSION['name'],$users)) {
// Eingeloggt und keine Berechtigung zum ändern
echo "<td>" . $current . "<br>" . $dates["name"][$position] . "</td>";
}
else {
// Nicht eingeloggt, oder keine Berechtigungen zum ändern des Kalenders
echo '<td>' . $current . '<br>belegt</td>';
}
}
else {
// Dieses Datum ist noch frei
if(isset($_SESSION['name']) and in_array($_SESSION['name'],$users)) {
// Eingeloggt und Berechtigung zum ändern
echo '<form action="index.php?s=calender" method="post">';
echo "<td>" . $current . "<br><input type=\"text\" name=\"name\"/ maxlength=\"20\"><input type=\"hidden\" name=\"date2\" value=\"$current;$month;$year\"/><input type=\"submit\" value=\"eintragen\"></td>";
echo '</form>';
}
else {
echo '<td>' . $current . '<br>frei</td>';
}
}
}
else {
// Nach der Monatsausgabe
$finished = true;
echo "<td> - </td>";
}
}
else {
// Wenn die Monatsausgabe noch nicht angefangen hat
if(($i+1) > 6 or ($i+1) == $starttag) {
// Anpassung wegen mktime und dem Parameter w, wo Sonntag = 0 gilt bzw.
// Wenn der gewählte Monat angefangen hat
$started = true;
$k -= 1;
$current = $k_old - $k;
$position = array_search($current,$dates["day"]);
if($position !== false) {
// Wenn was auf diesem Feld eingetragen wurde
if(isset($_SESSION['name']) and in_array($_SESSION['name'],$users)) {
// Eingeloggt und Berechtigung zum ändern
echo '<form action="index.php?s=calender" method="post">';
echo "<td>" . $current . "<br>" . $dates["name"][$position] . "<br><input type=\"hidden\" name=\"date\" value=\"$current\"/><input type=\"submit\" value=\"Löschen\"/></td>";
echo '</form>';
}
else {
// Nicht eingeloggt, oder keine Berechtigungen zum ändern des Kalenders
echo '<td>' . $current . '<br>belegt</td>';
}
}
else {
// Dieses Datum ist noch frei
if(isset($_SESSION['name']) and in_array($_SESSION['name'],$users)) {
// Eingeloggt und Berechtigung zum ändern
echo '<form action="index.php?s=calender" method="post">';
echo "<td>" . $current . "<br><input type=\"text\" name=\"name\" maxlength=\"20\"/><input type=\"hidden\" name=\"date2\" value=\"$current;$month;$year\"/><input type=\"submit\" value=\"Eintragen\"/></td>";
echo '</form>';
}
elseif(isset($_SESSION['name']) and !in_array($_SESSION['name'],$users)) {
// Eingeloggt und keine Berechtigung zum ändern
echo "<td>" . $current . "<br>" . $dates["name"][$position] . "</td>";
}
else {
echo '<td>' . $current . '<br>frei</td>';
}
}
}
else {
// Wenn die Monatsausgabe noch nicht angefangen hat
echo "<td> - </td>";
}
}
}
echo "</tr>";
}
echo "<table><br>";
Das ganze ist ein Kalender in PHP, den ich selber geschrieben habe, wo man sich in den Kalender Dinge eintragen kann, die gespeichert werden, wenn man die benötigten Rechte hat. So weit so gut. Allerdings tritt ein Fehler auf, bei dessen Suche ich auf etwas sehr komisches gestoßen bin. Während beim Laden der Seite überprüft wird, ob Änderungen am Kalender vorgenommen werden müsse (also als $_POST[date] und $_POST[date2] überprüft werden beim oberen Teil des Scripts, ist in $_SESSION['name'] der richtige eingeloggte User gespeichert. Weiter unten, wenn wir zum Kalenderteil kommen, ist in $_SESSION['name']allerdings aufeinmal der Inhalt des jeweiligen Kalendertages, in $_SESSION['name'] gespeichert. Daraufhin bin ich meinen gesamten Code Stück für Stück durchgegangen und habe nach einer Stelle gesucht wo ich aus Versehen $_SESSION['name'] den Wert des aktuellen Kalendertages (aktuell = der Kalendertag in dessen Schleifendurchlauf wir gerade sind) zuorden - diese Stelle existiert aber nicht! Die einzigen male, dass $_SESSION['name']in meinem Code vorkommt, sind die, wo ich mit if überprüfe, ob man eingeloggt ist, etc. Das heißt in meinem Code ändere ich also überhaupt nicht den Inhalt von $_SESSION['name']!!!
Wie kann es nun aber sein, dass wenn ich zweimal var_dump($_SESSION['name']); einfüge - einmal weiter oben im Code und einmal weiter unten bei der Monatsausgabe, dass zwei unterschiedliche Werte rauskommen, wodurch der eigentliche Fehler produziert wird?
Vielen Dank - ich stehe da gerade auf dem Schlauch!
Lieber Patrick Hartwig,
ich habe gerade keine Zeit, Deinen Code komplett durchzuschauen, daher lege ich den Finger auf die Stellen, die mir sehr verdächtig vorkommen:
// Wenn ein Eintrag gelöscht wird
$day = $_POST['date'];
mysql_query("DELETE FROM calender WHERE day = '$day' AND month = '$month' AND year = '$year'");
Hier hast Du eine SQL-Injection-Lücke. Was macht Dein Code, wenn ein Angreifer mittels POST folgendes (oder so ähnlich!) übermittelt?
date=SET%20PASSWORD%20FOR%20user%3DPASSWORD('some%20password')
Liebe Grüße,
Felix Riesterer.
--
ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
Hallo und erstmal Danke für deine Antwort,
nein, das ist keine Lücke. Da date und date2 immer nur automatisch festgelegte Werte vom Script zugewiesen bekommen und der Nutzer / Angreifer null Chance hat date oder date2 mit einem eigenem Wert zu belegen.
Stell dir das so vor, dass du eine Website in Form eines Kalenders hast und wenn ein Tag noch nicht belegt ist, entweder was reinschreiben kannst, womit dieser Tag dann belegt ist, oder einen der belegten Tage einfach löschen und damit freimachen kannst. Beides geschieht über eine <input type="hidden">, womit der date und date2 Wert festgelegt ist. Das einzige wo Benutzereingaben zustande kommen ist $_POST['name'], dass ich aber escape.
Zu meiner eigentlichen Frage: Ich habe jetzt mal an verschiedenen Stellen des Scripts mir var_dump($_SESSION); ausgeben lassen und konnte die Stelle jetzt auf 10 Zeilen einschränken .
elseif(isset($_POST['date2']) and isset($_POST['name']) and !empty($_POST['name'])) {
echo "test 1: ";
var_dump($_SESSION);
echo "<br><br>";
// Wenn ein neuer Eintrag geschrieben wird
$name = htmlentities($_POST['name'], ENT_QUOTES);
$date = $_POST['date2'];
$date = explode(";",$date);
$inputday = $date[0];
$inputmonth = $date[1];
$inputyear = $date[2];
mysql_query("INSERT INTO calender (day,month,year,name) VALUES ('$inputday','$inputmonth','$inputyear','$name')");
}
echo "test 2: ";
var_dump($_SESSION);
echo "<br><br>";
Ausgabe:
test 1: array(1) { ["name"]=> &string(9) "User" }
test 2: array(1) { ["name"]=> &string(3) "Content" }
Hi,
nein, das ist keine Lücke.
Und ob das eine ist.
Da date und date2 immer nur automatisch festgelegte Werte vom Script zugewiesen bekommen und der Nutzer / Angreifer null Chance hat date oder date2 mit einem eigenem Wert zu belegen.
Natürlich hat er, die Werte werden doch per Formular übermittelt.
Stell dir das so vor, dass du eine Website in Form eines Kalenders hast und wenn ein Tag noch nicht belegt ist, entweder was reinschreiben kannst, womit dieser Tag dann belegt ist, oder einen der belegten Tage einfach löschen und damit freimachen kannst. Beides geschieht über eine <input type="hidden">, womit der date und date2 Wert festgelegt ist.
Niemand hindert mich, in eines dieser versteckten Inputfelder z.B. mit Firebug einen anderen Wert einzutragen, bevor ich das Formular abschicke.
(Und niemand hindert mich, dir einen POST-Request mit einem HTTP-Client, der nicht mal ein „Browser“ ist, zu schicken.)
Das einzige wo Benutzereingaben zustande kommen ist $_POST['name'], dass ich aber escape.
Auch $_POST['date'] und $_POST['date2'] werden durch den Client übermittelt – das ist das *einzige* Kriterium, das hier Bedeutung hat – und sind deshalb als unsicher zu betrachten.
Bitte augenblicklichst den Artikel:Kontextwechsel im Wiki durcharbeiten(!), komplett. Erst danach mit irgendwas anderem weitermachen.
MfG ChrisB
Lieber ChrisB,
Bitte augenblicklichst den Artikel:Kontextwechsel im Wiki durcharbeiten(!), komplett. Erst danach mit irgendwas anderem weitermachen.
darauf ein "fachlich hilfreich"!
Liebe Grüße,
Felix Riesterer.
Hallo,
offenbar weist Du dem Session-Array-Key "name" eine Referenz auf die Variable "name" zu (erkennbar am "&"-Zeichen bei der Ausgabe von var_dump()) - wird der Wert der Variable "name" geändert, ändert sich also auch der entspr. Wert im Session-Array:
$hello = "hello";
$a = array('say' => &$hello);
var_dump($a);
// array(1) { ["say"]=> &string(5) "hello" }
$hello = "world";
var_dump($a);
// array(1) { ["say"]=> &string(5) "world" }
Ich vermute dass die Zuweisung der Werte in Deinem Fall noch anders (komplizierter) aussieht, da die Längenangabe bei den Strings abweichend von den ausgegebenen Strings ist.
Gruss,
Worf
Tach!
Während beim Laden der Seite überprüft wird, ob Änderungen am Kalender vorgenommen werden müsse (also als $_POST[date] und $_POST[date2] überprüft werden beim oberen Teil des Scripts, ist in $_SESSION['name'] der richtige eingeloggte User gespeichert. Weiter unten, wenn wir zum Kalenderteil kommen, ist in $_SESSION['name']allerdings aufeinmal der Inhalt des jeweiligen Kalendertages, in $_SESSION['name'] gespeichert.
Wie hast du das festgestellt?
Daraufhin bin ich meinen gesamten Code Stück für Stück durchgegangen und habe nach einer Stelle gesucht wo ich aus Versehen $_SESSION['name'] den Wert des aktuellen Kalendertages (aktuell = der Kalendertag in dessen Schleifendurchlauf wir gerade sind) zuorden - diese Stelle existiert aber nicht!
Hast du das nur mit den Augen gemacht oder hast du mit Kontrollausgaben die Fehlerfreiheit kontrolliert?
Wie kann es nun aber sein, dass wenn ich zweimal var_dump($_SESSION['name']); einfüge - einmal weiter oben im Code und einmal weiter unten bei der Monatsausgabe, dass zwei unterschiedliche Werte rauskommen, wodurch der eigentliche Fehler produziert wird?
Ah, var_dump() ist die Antwort auf meine erste Frage. Und nun beweg die beiden var_dump()s aufeinander zu und kreise so die Stelle ein, vor der der Wert noch stimmte und danach nicht mehr.
dedlfix.
Ergänzung
Ah, var_dump() ist die Antwort auf meine erste Frage. Und nun beweg die beiden var_dump()s aufeinander zu und kreise so die Stelle ein, vor der der Wert noch stimmte und danach nicht mehr.
Es kann ja nicht schaden, ein paar mehr der verwendeten Variablen zu beobachten. Beispielsweise so.
<?php
echo "<h2>Kontrollausgaben</h2>";
echo "<h3>SESSION-Array</h3>";
echo "<pre>";
var_dump ($_SESSION);
echo "</pre>";
echo "<h3>POST-Array</h3>";
echo "<pre>";
var_dump ($_POST);
echo "</pre>";
echo "<h3>GET-Array</h3>";
echo "<pre>";
var_dump ($_GET);
echo "</pre>";
echo "<h3>Datenbankabfrage</h3>";
echo "<p>$abfrage</p>";
echo "<h3>MySQL-Error</h3>";
echo "<p>Nr: " . mysql_errno() . "</p>";
echo "<p>" . mysql_error() ."</p>";
echo "<h3>Abfrageergebnis</h3>";
echo "<pre>";
var_dump ($abfrageergebnis);
echo "</pre>";
?>
Matthias
Lieber Matthias Apsel,
das lässt sich wunderbar in eine Funktion auslagern... da spart man dann Tipparbeit.
Liebe Grüße,
Felix Riesterer.
Om nah hoo pez nyeetz, Felix Riesterer!
das lässt sich wunderbar in eine Funktion auslagern... da spart man dann Tipparbeit.
Bei mir ist es ein include. Spart auch.
Matthias
Hallo!
Wie kann es nun aber sein, dass wenn ich zweimal var_dump($_SESSION['name']); einfüge - einmal weiter oben im Code und einmal weiter unten bei der Monatsausgabe, dass zwei unterschiedliche Werte rauskommen, wodurch der eigentliche Fehler produziert wird?
Vielleicht ist hier register_globals auch ein Stichwort (hab dein Codebeispiel nicht genau angeguckt, sich seltsam ändernde Variable riecht aber danach).
Mal probieren, alle $name in zB $test_name zu ersetzen und auszugeben.
Schönen Abend,
Jonny 5