Sven Rautenberg: PHPSESSID & MySQL

Beitrag lesen

Moin!

ich habe eine kleine frage!

Deine kleine Frage wird in eine große Antwort ausarten.

wieso wenn ich diesen script starte "index.php" und "login.php" kann ich mich problemlos einlogen aber sobald ich auf einer anderen seite gehen möchte mit dem selben script wie "login.php" springt der script auf die seite "index.php" zurück und fragt mich nach dem username und password????

Beschäftige dich mit Session-Handling!

Sessions werden in PHP grundsätzlich über eine von zwei Arten realisiert. Methode 1 ist die bessere: Ein Cookie. Methode 2 schleift die Session-ID per URL überall hin mit.

Bei Methode 1 wird versucht, dem Browser ein Cookie zu schicken. Das sollte schlauerweise schon auf der ersten Seite passieren - wenn ich deinen Ablauf aber richtig verstanden habe, dann reicht es auch noch, auf der zweiten, überprüfenden Seite ein Cookie zu setzen. Weil das Cookie gesetzt ist, werden bei weiteren Seitenaufrufen die Session-Daten erneut geladen.

Bei Methode 2 werden die Daten, die normalerweise im Cookie stehen (nämlich "PHPSESSID=diesessionid") über die URL oder versteckte Formularfelder weitergetragen. Diese Methode ist etwas unsicherer, weil diese Daten leichter verlorengehen können.

Außerdem kann man Pech haben und muß sich um die Weitergabe dieser Daten selbst kümmern. PHP kennt zwar einen Modus, in dem es jede ausgegebene URL in Links und jedes Formular erkennt und mit der Session-ID anreichert - wenn dieser Modus, der natürlich Performance kostet, aber abgeschaltet ist, muß man selber für die Weitergabe sorgen.

Damit das aber möglichst leicht wird, generiert PHP immer eine Konstante namens "SID", die man einfach an alle URLs dranhängen kann. Wenn kein Cookie festgestellt wurde, ist in der Konstanten die korrekte Zeichenfolge für die URL enthalten, wenn aber Cookies festgestellt wurden, ist die Konstante leer (und stört nicht in der URL).

<a href="login.php?PHPSESSID=<? echo PHPSESSID; ?>">Link</a>

Deshalb solltest du diesen Link besser so schreiben:
<a href="login.php?<? echo SID; ?>">Link</a>

Das gilt aber auch für _sämtliche_ anderen Links auf deiner Seite. Die müssen alle die Session-ID mitschleifen, sofern du nicht zwingend Cookies voraussetzen willst.

ich möchte verstehen wieso der script immer wieder auf "index.php" zurück springt. under linux funktioniert es perfekt. hat es was zu tun mit der "php.ini" datei?

Die Einstellungen in der PHP.INI haben natürlich Einfluß darauf, wie PHP arbeitet.

Es ist sinnvoll, für das Entwicklungssystem die gleichen Einstellungen zu wählen, die auch auf dem Liveserver vorhanden sind. Insbesondere ist es auch sinnvoll, die gleiche PHP-Version zu verwenden. Und wenn das nicht exakt geht: Zwischen PHP 4.0.x (und davor) und 4.1.x (und danach) haben die Entwickler diverse Dinge grundsätzlich geändert. Und das ist alles zum Vorteil für PHP-Programmierer gewesen. Du solltest also auf deinem Windows-Server dann PHP 4.3.1 benutzen, wenn dein Live-Server mindestens PHP 4.1.0 einsetzt. Wenn nicht, solltest du den Provider mal drängen, ein Update zu machen. Vielleicht kann er deine Website auch auf einen anderen Server transferieren, auf der ein neueres PHP installiert ist.

Außerdem muß ich deinen Programmierstil grundsätzlich kritisieren:

***************************************login.php*******************************

<? include("./options.php"); ?>

<?
include ("./common_db.php");
$register_script = "./register.php";

function auth_user($username, $password) {
   global $default_dbname, $user_tablename;

Das Verwenden der Direktive "global" zeugt von ganz schlechtem Programmierstil. Man greift nicht aus Funktionen heraus auf globale _Variable_ zu.

Du willst offenbar gewisse Einstellungen zentral verwalten und an den jeweiligen Stellen darauf zugreifen. Dann definiere dir passende Konstanten mit define(). Diese Konstanten sind überall in den Funktionen verfügbar und haben außerdem noch den unschätzbaren Vorteil, dass sie auch durch Script- und Hackerunfälle nicht geändert werden können. Du erhöhst damit definitiv die Sicherheit deiner Skripte.

http://www.php.net/define

$link_id = db_connect($default_dbname);
   $query = "SELECT username FROM userinfo
                             WHERE username = '$username'
                             AND password = '$password'";

Oha, noch eine mögliche Falle: Hast du irgendwo geprüft, ob in $username oder $passwort Zeichen drinstehen, die MySQL durcheinanderbringen könnten? Ich sehe nichts. Zwar hat PHP eine Funktion, die vom Browser gesendeten Werten automatisch Backslashes hinzufügt (alle ', " und \ kriegen ein \ vorangestellt - genau wie bei addslashes()), aber diese Funktion nervt eigentlich nur, weil man nicht alle Daten immer in eine Datenbank packen will. Die Direktausgabe muß man dann aber immer mit stripslashes() filtern. Und außerdem ist zum Escapen von Zeichenketten für MySQL die Funktion mysql_escape_string() viel besser geeignet. Sie escapet beispielsweise auch das Prozentzeichen, welches ansonsten als Platzhalter wirken könnte und vollkommen unerwartete Suchergebnisse provozieren würde.

http://www.php.net/mysql-escape-string

$result = mysql_query($query);

if(!mysql_num_rows($result)) return 0;
   else {
      $query_data = mysql_fetch_row($result);
      return $query_data[0];
   }
}

function login_form() {
   global $PHP_SELF;

Und noch ein faux pas.

In neuen PHP-Skripten solltest du niemals mehr davon ausgehen, dass register_globals aktiviert ist. Das Entwicklerteam hat seit Version 4.1.0 die superglobalen Variablen $_GET, $_POST, $_SERVER etc. eingeführt und schreibt seitdem davon, dass die Standardeinstellung von register_globals künftig auf "aus" stehen wird. Diese bringt einen sehr wesentlichen Schritt hin zu mehr Sicherheit bei Scripten, weil nicht mehr beliebige globale Variablen vom Benutzer eingeschleppt werden können.

Verwende also statt $PHP_SELF lieber die globale Variable $_SERVER['PHP_SELF']. Sie ist suberglobal, d.h. auch in Funktionen ohne global-Direktive verfügbar.

?>

<?
// LOGIN
        include("./index.php");
endif;
// LOGIN
?>

Wozu dieses ENDIF? Es paßt hier definitiv nicht hin, außerdem gehört es zu der alternativen IF-ELSE-ENDIF-Schreibweise, die ich nicht empfehlen würde - insbesondere weil du die normale Schreibweise mit geschweiften Klammern auch verwendest.

<?
}

session_start();
if(!isset($username)) {
  login_form();
  exit;
}

else {
  session_register("username", "password");

Der Befehl session_register() sollte ebenfalls nicht mehr verwendet werden. Die neue Art der Variablenübergabe ist viel simpler. Du hast ein Array namens $_SESSION, in welches du beliebige Werte speichern kannst. Beispielsweise so: $_SESSION['username'] = $_POST['username']. Das Array $_SESSION wird von PHP automatisch bei einer gestarteten Session gesichert und auf der neuen Seite mit den bisher gespeicherten Werten wieder neu geladen, sobald session_start() ausgeführt wird.

$username = auth_user($username, $password);
  if(!$username) {
    session_unregister("username");
    session_unregister("password");

Was meinst du: Wäre es nicht sinnvoller, _erst_ zu prüfen, ob Username und Passwort zueinander passen, und _dann_ diese Information in der Session zu speichern?

Abgesehen davon ist deine Auth-Funktion bzw. das Überschreiben des Usernamens nicht unbedingt glücklich gelöst. Ich würde sowas nicht so machen. Besser:

if (auth($_POST['username'],$_POST['password']))
{
  $_SESSION['username'] = $_POST['username'];
  $_SESSION['password'] = $_POST['password'];
}

?>

<?
// ERROR LOGIN
        include("./login_error.php");
endif;

Schon wieder so ein endif. Wozu?

// ERROR LOGIN
?>

<?
  exit;
  }
?>

<html>
...

<!-- CONTENT HERE -->

<center>
  <a href="login.php?PHPSESSID=<? echo PHPSESSID; ?>">Link</a>

Das Thema hab ich oben ausführlich erklärt...

</center>

<!-- CONTENT HERE -->

...
</html>

<?
}
?>

- Sven Rautenberg

--
ss:) zu:) ls:[ fo:} de:] va:) ch:] sh:) n4:# rl:| br:< js:| ie:( fl:( mo:|