Loginscript
Diese Codebeispiel zeigt euch, wie ihr MySQL und Sessions verwendet um eine sicheren Login-Bereich für eure Website zu haben. Solltet ihr die Nutzerdaten bisher in eine Textdatei abgespeichert haben, so solltet ihr schnellstmöglich umsteigen und MySQL verwenden. Dieses Script könnt ihr hier herunterladen.
Inhaltsverzeichnis
Datenbankstruktur
Als erstes legt ihr mittels phpMyAdmin eine neue Tabelle an. Ihr könnt dabei die gleiche Tabelle wie bereits aus dem MySQL-Tutorial verwenden:
Beziehungsweise der nötige SQL-Code für diese Tabelle ist:
1 2 3 4 5 6 7 8 9 10 |
CREATE TABLE `users` ( `id` INT NOT NULL AUTO_INCREMENT , `email` VARCHAR(255) NOT NULL , `passwort` VARCHAR(255) NOT NULL , `vorname` VARCHAR(255) NOT NULL DEFAULT '' , `nachname` VARCHAR(255) NOT NULL DEFAULT '' , `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `updated_at` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`), UNIQUE (`email`) ) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; |
Als nächstes erzeugt ihr eine neue Zeile in eurer Tabelle für einen neuen Benutzereintrag. Tragt in die Tabelle mittels phpMyAdmin einen neuen Test-Benutzer ein, beispielsweise mit den Daten:
E-Mail: [email protected]
Passwort: $2y$10$qCgb4MKzbMKAqUU2LOFBQ.wGoAD6yBElFA7V7EPwK.QGCViJjx4mu
Das kryptisch aussehende Passwort ($2y$10$qCgb4MKzbMKAqUU2LOFBQ.wGoAD6yBElFA7V7EPwK.QGCViJjx4mu) ist dabei der password_hash-Hashwert vom Passwort test. Diesen Wert könnt ihr mit unserem Hashwert Generator erzeugen. Ihr solltet Passwörter niemals im Klartext abspeichern. Ein Angreifer könnte sonst bei einem Diebstahl eurer User-Tabelle großen Schaden anrichten. Das Abspeichern als Hashwert bietet dabei einen gewissen Schutz gegen Angriffe. Mehr Infos zu dem Thema findet ihr im Artikel Passwörter sicher speichern sowie in unserem Tutorial PHP Sicherheit.
Damit ihr die password_hash()-Funktion nutzen könnt, müsst ihr bzw. eurer Webhoster mindestens PHP 5.5 nutzen. Falls ihr PHP >= 5.3.7 oder PHP 5.4 noch verwendet, ladet die password.php herunter und bindet diese per include("password.php"); zu Beginn eurer Scripts ein.
Dateiaufbau
Für dieses Beispiel benötigt ihr die folgenden Dateien:
- registrieren.php - Eure Datei für die Benutzerregistrierung
- login.php - Eure Datei für den Login
- geheim.php - Euer geschützter Bereich
Registrierung
Das komplette Script für die Registrierung sieht wie folgt aus. Weiter unten findet ihr eine genauere Erläuterung.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<?php session_start(); $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', ''); ?> <!DOCTYPE html> <html> <head> <title>Registrierung</title> </head> <body> <?php $showFormular = true; //Variable ob das Registrierungsformular anezeigt werden soll if(isset($_GET['register'])) { $error = false; $email = $_POST['email']; $passwort = $_POST['passwort']; $passwort2 = $_POST['passwort2']; if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { echo 'Bitte eine gültige E-Mail-Adresse eingeben<br>'; $error = true; } if(strlen($passwort) == 0) { echo 'Bitte ein Passwort angeben<br>'; $error = true; } if($passwort != $passwort2) { echo 'Die Passwörter müssen übereinstimmen<br>'; $error = true; } //Überprüfe, dass die E-Mail-Adresse noch nicht registriert wurde if(!$error) { $statement = $pdo->prepare("SELECT * FROM users WHERE email = :email"); $result = $statement->execute(array('email' => $email)); $user = $statement->fetch(); if($user !== false) { echo 'Diese E-Mail-Adresse ist bereits vergeben<br>'; $error = true; } } //Keine Fehler, wir können den Nutzer registrieren if(!$error) { $passwort_hash = password_hash($passwort, PASSWORD_DEFAULT); $statement = $pdo->prepare("INSERT INTO users (email, passwort) VALUES (:email, :passwort)"); $result = $statement->execute(array('email' => $email, 'passwort' => $passwort_hash)); if($result) { echo 'Du wurdest erfolgreich registriert. <a href="login.php">Zum Login</a>'; $showFormular = false; } else { echo 'Beim Abspeichern ist leider ein Fehler aufgetreten<br>'; } } } if($showFormular) { ?> <form action="?register=1" method="post"> E-Mail:<br> <input type="email" size="40" maxlength="250" name="email"><br><br> Dein Passwort:<br> <input type="password" size="40" maxlength="250" name="passwort"><br> Passwort wiederholen:<br> <input type="password" size="40" maxlength="250" name="passwort2"><br><br> <input type="submit" value="Abschicken"> </form> <?php } //Ende von if($showFormular) ?> </body> </html> |
Wir starten die Registrierung indem wir zuerst session_start() aufrufen und dann eine Verbindung zur Datenbank aufbauen. Hier haben wir als Datenbank test gewählt mit dem Datenbanknutzer root und einem leeren Passwort.
Das Formular zur Registrierung beginnt ab Zeile 50. Um zu steuern ob wir das Registrierungsformular ausgeben wollen haben wir die Variable $showFormular definiert. Standardmäßig (Zeile 13) ist der Wert true. Das Registrierungsformular ist ein schlichtes HTML-Formular welches die Daten an die eigene Seite sendet, aber zusätzlich noch den GET-Parameter register=1 mit übergibt. So können wir später leicht überprüfen, ob Daten für die Registrierung gesendet wurde (Zeile 15).
Mittels isset($_GET['register']) in Zeile 15 überprüfen wir ob der GET-Parameter übergeben wurde, sprich, ob das Formular für die Registrierung abgesendet wurde. Danach fragen wir die Daten aus dem Formular ab und überprüfen zum einem mittels filter_var() ob die E-Mail-Adresse gültig ist und dass die zwei Passwörter identisch sind. Sollte kein Fehler aufgetreten sein, so führen wir die Registrierung durch.
Ab Zeile 35 überprüfen wir, dass die E-Mail-Adresse noch nicht in der Tabelle vorhanden ist. Dazu senden wir einen entsprechenden SELECT-Query an die Datenbank und falls ein Benutzer gefunden wird, sprich, falls $user !== false, geben wir die Fehlermeldung zurück, dass die E-Mail-Adresse bereits vergeben ist.
Wie oben beschrieben berechnen wir erst mittels password_hash() den Hashwert des Passworts. Danach bereiten wir unseren SQL-Query vor zum Eintrag des neuen Nutzers (mehr Infos zum Thema Daten einfügen). Sollte alles geklappt haben, so geben wir eine Erfolgsmeldung aus und setzen die Variable $showFormular auf false. Dadurch verhindern wir im Erfolgsfall, dass das Registrierungsformular nochmal ausgegeben wird.
Übungsaufgabe
- Erweitert das Registrierungsformular um weitere Felder, z.B. für den Vorname und den Nachname
Login
Unsere login.php ist ziemlich einfach aufgebaut:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php session_start(); $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', ''); if(isset($_GET['login'])) { $email = $_POST['email']; $passwort = $_POST['passwort']; $statement = $pdo->prepare("SELECT * FROM users WHERE email = :email"); $result = $statement->execute(array('email' => $email)); $user = $statement->fetch(); //Überprüfung des Passworts if ($user !== false && password_verify($passwort, $user['passwort'])) { $_SESSION['userid'] = $user['id']; die('Login erfolgreich. Weiter zu <a href="geheim.php">internen Bereich</a>'); } else { $errorMessage = "E-Mail oder Passwort war ungültig<br>"; } } ?> <!DOCTYPE html> <html> <head> <title>Login</title> </head> <body> <?php if(isset($errorMessage)) { echo $errorMessage; } ?> <form action="?login=1" method="post"> E-Mail:<br> <input type="email" size="40" maxlength="250" name="email"><br><br> Dein Passwort:<br> <input type="password" size="40" maxlength="250" name="passwort"><br> <input type="submit" value="Abschicken"> </form> </body> </html> |
Sollte das Login-Formular abgesendet worden sein, sprich, wenn der GET-Parameter login gesetzt ist, fragen wir zuerst die Datenbank nach der entsprechenden E-Mail-Adresse ab. Sollte kein Benutzer gefunden worden sein, so hat der $user den Wert false.
Um das Passwort zu überprüfen nutzen wir den folgenden Code:
password_verify($benutzer_eingabe, $gespeichertes_passwort)
password_hash() erzeugt bei mehrmaligem Aufruf unterschiedliche Hashwerte selbst bei identische Passwörtern. Deswegen funktioniert es nicht, nur die Benutzereingabe zu hashen und diesen Hashwert zum existenten Hashwert zu vergleichen. Mit der obigen Variante funktioniert aber das Abgleich des Passworts.
Sollte also ein Nutzer gefunden worden sein und sollte das Passwort stimmen, so registrieren wir die Session-Variable userid mit der ID des Benutzers und beenden den weiteren Script-Verlauf.
Geschützter Bereich
Für unseren geschützten Bereich (geheim.php) müssen wir nur überprüfen, ob die Session-Variable userid existiert. Falls nicht, weisen wir den Nutzer darauf hin, dass sich dieser zuerst registrieren muss.
1 2 3 4 5 6 7 8 9 10 11 |
<?php session_start(); if(!isset($_SESSION['userid'])) { die('Bitte zuerst <a href="login.php">einloggen</a>'); } //Abfrage der Nutzer ID vom Login $userid = $_SESSION['userid']; echo "Hallo User: ".$userid; ?> |
Diesen Codeschnipsel müsst ihr nun nur einfach in jede eurer geschützten Seiten einbauen.
Logout
Solltet ihr noch an einem Logout interessiert sein, so fügt einfach in eine neue Datei, beispielsweise in die logout.php folgenden Code ein:
1 2 3 4 5 6 |
<?php session_start(); session_destroy(); echo "Logout erfolgreich"; ?> |
Autor: Nils Reimers