Kennwortschutz und Authentifizierung in PHP

Nicht jeder Nutzer hat überall auf Ihrem Server etwas zu suchen. Beim Schutz von Dokumenten sind Usernamen und Kennwörter gefragt. Dieser in Internet Professionell erschienene Beitrag zeigt, wie Sie selbst mit PHP und MySQL einen einfachen Schutz vor unbefugtem Zugriff programmieren.

Der Bedarf seine Web-Dokumente zu schützen ist so hoch wie unterschiedlich. Der eine möchte nur eine einfache Hürde vor ein Dokument setzen, damit nicht jeder frei darauf zugreift. Der Andere braucht mehr Sicherheit, um eine Liste von Benutzern und Mail-Adressen zu verwalten: Nur wenn sich ein Benutzer mit Usernamen und Kennwort meldet, darf der seine eigene E-Mail-Adresse ändern.

Für beide Anwendungen gibt es in diesem Artikel eine Lösung. Anhand des ersten Beispiels erfahren Sie, wie Sie einen einfachen und schnellen Schutz in PHP implementieren – das geht sogar ohne MySQL. Das zweite Beispiel nutzt dann MySQL, um Nutzerdaten zu speichern und abzufragen.

Einfacher Schutzmechanismus

Um ein Dokument vor unbefugtem Zugriff zu schützen, packen Sie eine Authentifizierungsroutine hinein. PHP teilt über die Funktion header() dem Browser http-Kopfdaten mit. Und wenn dieser WWW-authenticate: meldet, erscheint im Browser das Abfragefenster für Usernamen und Kennwort.

Der Benutzer gibt hier seine Kennung und ein Passwort ein.

Diese beiden Werte speichert PHP in den Variablen $PHP_AUTH_USER und $PHP_AUTH_PW. Das Programm vergleicht diese Variablen mit einem vorgegebenen Usernamen und einem Kennwort. Stimmen sie überein, geht es weiter.

Wenn nicht, hat man noch zwei Versuche frei, bevor die Kennwortabfrage aufgibt und der Server einen »unerlaubten Zugriff« meldet. Das Programm sehen Sie in Listing 1.

<?

// Einfacher Username und Kennwort

// Achtung: Extrem unsicher, nur

// zu Demo-Zwecken

$NAME_REQUIRED = “ipro”;

$PW_REQUIRED = “test”;

//Authentifizierung

function authenticate()

{

Header(“WWW-authenticate: basic realm=”Internet Professionell””);

Header(“HTTP/1.0 401 Unauthorized”);

echo “Nicht berechtigt”;

exit;

}

// Ueberpruefen, ob schon ein User

// gesetzt ist, wenn nein,

// dann Kennwort abfragen

if (!isset($PHP_AUTH_USER))

authenticate();

else

{

if(($NAME_REQUIRED == $PHP_AUTH_USER) &&

($PW_REQUIRED == $PHP_AUTH_PW))

echo (“Hallo $PHP_AUTH_USER”);

else

authenticate();

}

?>

 

Zuerst legt das Programm Usernamen und Kennwort fest. Natürlich ist es gefährlich, diese Daten im Quelltext abzulegen. Doch für einen simplen Kennwortschutz reicht es, etwa wenn Sie einer bestimmten Personengruppe Informationen zugänglich machen wollen und wenn es nicht so schlimm ist, falls einmal jemand den Inhalt der Seite einmal sieht.

Es folgt die Funktion authenticate(), die für die Kennwort-Abfrage zuständig ist. Der Header benötigt neben WWW-authenticate: basic noch eine Bezeichnung für den Bereich. Diesen gibt das Anmeldefenster mit aus. Sinnvoll ist die Bezeichnung des Dienstes, hier mit realm=”Internet Professionell” angegeben. Beachten Sie, dass dieser Header in einer Zeile stehen muss.

Eine Zeile weiter steht der Header, der bei einem Scheitern der Anmeldung in Kraft tritt und den unbefugten Zugriff meldet.

Das Hauptprogramm sieht mit der Funktion isset() nach, ob schon eine Variable $PHP_AUTH_USER gesetzt ist. Wenn ja, geht es mit dem Überprüfen der Angaben weiter. Beim ersten Aufrufen der Datei allerdings sind diese Werte noch nicht gesetzt. Also ruft das Skript die Funktion authenticate() auf, um sich diese Variablen zu besorgen.

Beim erneuten Durchlauf der Abfrage hat das Hauptprogramm die gewünschten Daten. Es vergleicht sie mit den Vorgaben in den eingangs definierten $NAME_REQUIRED und $PW_REQUIRED. Stimmen sie, gibt es eine Begrüßung, wenn nicht startet authenticate() abermals.

Schutz aus der Datenbank

Etwas aufwändiger wird es, wenn Sie Nutzerdaten wie eine E-Mail-Adresse in einer Datenbank verwalten. Wegen seiner guten Zusammenarbeit mit PHP bietet sich MySQL als Werkzeug an um einerseits Nutzerdaten zu speichern und andererseits gleich noch zusätzliche Angaben wie eine E-Mail-Adresse unterzubringen.

Listing 2 stellt genau diese Tabelle her. Sie lesen die dort geschriebene Datei test.sql mit der Eingabe von

 

mysql -uroot -p < test.sql

 

in Ihre Datenbank ein. Diese Anweisung meldet Sie als Datenbankverwalter an und fragt nach dem Kennwort. Wenn Sie kein Passwort für die Datenbank vergeben haben, drücken Sie [Return] (und hängen Sie diesen Server niemals so ans Netz).

 

CREATE DATABASE test;

USE test;

CREATE TABLE users (

id varchar(20) DEFAULT ” NOT NULL,

password varchar(20),

mail varchar(50) DEFAULT ” NOT NULL

);

INSERT INTO users VALUES (

‘ipro’,

password(‘kw1’),

‘ipro@foo.bar’

);

INSERT INTO users VALUES (

‘test’,

password(‘test’),

‘test@foo.bar’

);

 

Nach dem Herstellen der neuen Datenbank test und der Tabelle users trägt das Skript gleich zwei User ein. Dabei nutzt es die Funktion password(), um die Kennwörter verschlüsselt in der Datenbank zu speichern.

Das Programm

Das Beispielprogramm in Listing 3 verwaltet eine Tabelle mit Usernamen, einem Kennwort und einer E-Mail-Adresse. Diese Adresse lässt sich zum Beispiel für eine Mailing-Liste verwenden. Im Normalfall sollte man die Adresse in einer gesonderten Tabelle speichern und spricht sie über eine Nutzer-ID an. Doch das würde in diesem Beitrag zu weit führen.

Vereinfacht funktioniert das Programm so:

– Das PHP-Skript sendet den Authentifizierungs-Header.

– Der Nutzer gibt seinen Namen und ein Kennwort ein.

– Das PHP-Skript öffnet die Tabelle mit den Nutzerdaten und durchsucht sie nach dem Usernamen.

– Anhand des Usernamen ermittelt das Skript das Kennwort und vergleicht es mit der Eingabe.

– Stimmen Username und Kennwort, darf der Benutzer seine E-Mail-Adresse ändern.

 

<?

//Verbindung zur Datenbank herstellen

function connect()

{

mysql_pconnect(“localhost”,”root”,””)

or die(“Keine Verbindung zum SQL server”);

 

mysql_select_db(“test”)

or die(“Kann Datenbank nicht auswaehlen: “.

mysql_error() . “) “);

}

 

//Authentifzierung starten

function authenticate()

{

Header(“WWW-authenticate: basic realm=”Internet Pro””);

Header(“HTTP/1.0 401 Unauthorized”);

echo “Nicht berechtigt”;

exit;

}

//Usernamen in Datenbank verifizieren

function verify_user($PHP_AUTH_USER, $PHP_AUTH_PW)

{

$pw_querystring =

“select * from users

where id=’$PHP_AUTH_USER’

and

password=password(‘$PHP_AUTH_PW’)”;

$result = mysql_query($pw_querystring);

if (!$result)

die(“<br><b>$PHP_SELF</b>: “.mysql_error());

else if(!mysql_num_rows($result))

authenticate();

else

return $result;

}

// Userdaten anzeigen

function show_data($user_data)

{

$row = mysql_fetch_array($user_data);

echo “Hallo <b>$row[id]</b>.<br>”;

?>

<form action=authent.php method=POST>

Ihre E-Mail:

<input type=text size=30 name=mail

value=<? echo $row[mail]; ?>>

<input type=hidden name=update value=1>

<input type=submit value=Ändern>

</form>

<?

}

// Mail-Adresse updaten

function update_mail($mail, $name)

{

$mail_querystring=”update users

set mail=”$mail”

where id=”$name””;

 

mysql_query($mail_querystring)

or die(“<br>Fehler mit: “.$mail_querystring);

}

 

/*

—————————

Hauptprogramm

—————————

*/

// Verbindung zur Datenbank herstellen

connect();

// Nachsehen ob es $PHP_AUTH_USER gibt

// wenn nein, Anmeldung erzwingen

if (!isset($PHP_AUTH_USER))

authenticate();

else if(!isset($update) || ($update <> 1))

{

// Nachsehen, ob User in Datenbank

if ($result=verify_user($PHP_AUTH_USER, $PHP_AUTH_PW))

{

echo “Anmeldung erfolgreich<br>”;

show_data($result);

}

}

// Ist es ein Update

if (isset($PHP_AUTH_USER) && ($update==1))

{

//Nochmal den User verifizieren

verify_user($PHP_AUTH_USER, $PHP_AUTH_PW);

update_mail($mail, $PHP_AUTH_USER);

if($result=verify_user($PHP_AUTH_USER, $PHP_AUTH_PW))

{

show_data($result);

echo “Update erfolgreich.”;

}

else

echo “Update fehlgeschlagen.”;

}

?>

 

Bevor es los geht stellt das Hauptprogramm mit connect() eine Verbindung zur Datenbank her. Dabei geht das Programm davon aus, dass kein Kennwort für den Datenbankzugriff vergeben wurde. Sie sollten die Zeile

 

mysql_pconnect(“localhost”,”root”,””)

 

entsprechend anpassen.

Dann überprüft das Skript, ob $PHP_AUTH_NAME und $PHP_AUTH_PW vorhanden sind. Wenn nicht, startet die Funktion authenticate(). Sind die beiden Variablen vorhanden, startet eine Datenbankabfrage. Sie ist in der Funktion verify_user() untergebracht. Die bekommt die User-Variablen mit auf den Weg, bereitet eine Datenbankabfrage vor und führt sie aus. Dabei schaut das Programm nach, ob der Username und das Kennwort in einem Datensatz vorkommen. Um den in der Tabelle verschlüsselten Zugangscode zu ermitteln, packt die Abfrage $PHP_AUTH_PW in die password()-Funktion. Nur falls Username und Kennwort stimmen, gibt die Abfrage und damit die Funktion ein Ergebnis zurück. Anderenfalls startet nochmals authenticate().

Das Ergebnis der Abfrage landet nach dem Funktionsaufruf

 

$result=verify_user($PHP_AUTH_USER, $PHP_AUTH_PW)

 

in der Variablen $result. Dieses Ergebnis dient der nächsten Funktion show_data($result) als Datenlieferant. Die Funktion zeigt eine freundliche Begrüßung sowie die E-Mail-Adresse des Nutzers in einem Formular. Dieses Formular ist der Einfachheit halber aus dem PHP-Code ausgeklammert. Mit einem ?> und <? nach dem HTML-Code erspart man sich lästige echo-Orgien.

Ändert der Nutzer seine Adresse und drückt er auf Ändern, ruft sich das Programm selbst noch einmal auf und übergibt dabei den Parameter $update=1. Daran erkennt das Hauptprogramm den Änderungswunsch. Nach einer erneuten Sicherheitsüberprüfung wird der Datensatz des Nutzers auf den neuen Stand gebracht. Das Formular übergibt die Daten mit der POST-Methode — damit bleiben die Parameter unsichtbar. Wenn Sie zu Testzwecken die übergebenen Werte sehen wollen, setzen Sie an Stelle von

 

<form action=authent.php method=POST>

 

die Zeile

 

<form action=authent.php method=GET>

 

Nach dem Ändern wird die Verifizierung erneut aufgerufen — allerdings nur, um an das neue $result zu kommen. Der aufgefrischte Datensatz erscheint dann samt einer Erfolgsmeldung im Browser-Fenster.

Ein Test

Nun ist es Zeit für einen ersten Test. Rufen Sie das Programm aus Ihrem Browser heraus auf. Sie sehen die Eingabenmaske für Usernamen und Kennwort. Tippen Sie ipro und als Kennwort kw1 ein. Alternativ verwenden Sie test und test. Nach dem Aufruf sehen Sie die Mail-Adresse ipro@foo.bar, die Sie nach Belieben ändern dürfen. Klicken Sie auf Ändern und Sie sehen die neue Adresse gleich wieder im Formular.

Auffällig ist: Wenn Sie das Programm erneut aufrufen, erscheint die Authentifizierung nicht mehr. Denn Browser wie der Netscape Navigator und der Internet Explorer führen einmal definierte Usernamen während der gesamten Browser-Sitzung mit. So reicht es, wenn Username und Kennwort nur einmal festgelegt werden. Andere Dokumente können dann immer wieder diese Benutzerdaten abfragen und ersparen dem Leser so die erneute Eingabe.

Userdaten verwalten

Um die Nutzerdaten zu diesem Programmbeispiel zu verwalten, setzen Sie am besten PhpMyAdmin ein. Hier können Sie von jedem Browser aus neue Nutzer eintragen. Denken Sie aber daran, bei jedem Neueintrag das Kennwort mit zugeschalteter PASSWORD-Funktion einzutragen. Mehr Information zu PhpMyAdmin finden Sie im Internet unter http://phpwizard.net/projects/phpMyAdmin/.

So geht es weiter

Wenn Sie weiter mit diesen Beispielen arbeiten wollen, sollten Sie zunächst die User-Tabelle und die E-Mail-Adressen trennen. In einer neuen Tabelle bringen Sie dann neben der E-Mail noch weitere persönliche Daten der Nutzer unter. Je nach Wunsch können Sie diese Daten zum Ändern oder löschen frei geben.

Wenn Sie den Usern einen Weg eröffnen wollen, sich selbst in die Datenbank einzutragen, sollten Sie an einen Abgleich des neu eingegebenen Usernamens mit den bereits vorhandenen Usernamen denken.

Für einen universellen Einsatz der Benutzerauthentifizierung sollten Sie die Funktion authenticate() und den Abgleich der Userdaten mit der MySQL-Tabelle in eine Include-Datei packen, die Sie je nach Bedarf hinzulinken. Auf diese Weise können Sie mit einem einzigen Funktionsaufruf bestimmen, ob ein Dokument geschützt sein soll.

Achtung: Bitte beachten Sie, dass es sich auch hier um Beispiele handelt, die allenfalls zum Testen geeignet sind und an Ihren Bedarf angepasst werden müssen.

Ähnliche Beiträge