Zurück

Datenbankgestützter Zugangsschutz mit Apache::AuthDBI

  1. Konventionelle Authentifizierung
  2. Datenbankgestützte Authentifizierung
  3. Zugangsschutz im Hypertext-Transfer-Protocol (http)
  4. Minimalversion einer Datenbank zur User-Authentifizierung
  5. Konfiguration des Apache-Webservers

Konventionelle Authentifizierung

Fast allen die sich schon mal länger im Internet getummelt haben kennen zugangsgeschützte Seiten. Beim Versuch auf solche Seiten zuzugreifen wird man erst aufgefordert sich zu identifizieren.

Authentifizierung durch Abfrage von Benutzername und Paßwort

Abb. 1: Das Authentifizierungsfenster

Die Konfiguration eines zugangsgeschützten Bereichs erfolgt bei dem weitverbreiteten Webserver Apache entweder direkt in der Konfigurationsdatei (httpd.conf) oder innerhalb einer Art "Unter"-Konfigurationsdatei. Letztere hat üblicherweise den Dateinamen ".htaccess" (der Punkt am Anfang des Dateinamens ist kein Schreibfehler). Sowohl der Name dieser Datei als auch die Festlegung welche Subkonfiguration hier erlaubt ist wird in der httpd.conf vorgenommen.

AccessFileName .htaccess
<Files ~ "^\.ht">
  Order allow,deny
  Deny from all
</Files>
<Directory /home/*/public_html>
  AllowOverride FileInfo AuthConfig Limit
</Directory>
Tabelle 1: Konfigurationsbsp. aus der httpd.conf

Die erste Zeile legt den Dateinamen fest, der folgende Files-Block verhindert die Anzeige der Dateien im Clientbrowser und die AllowOverride-Direktive im anschließenden Directory-Block legt die Konfigurations-Möglichkeiten der .htaccess-Dateien fest.

Die beim Apache-Webserver bereits mitgelieferten Zugangsschutz-Werkzeuge sehen eine Benutzerdatei vor in der die einzelnen Zugangsberechtigten aufgelistet sind. Das Dateiformat selbst entspricht grob den passwd-Dateien (bzw. shadow-Dateien) eines Unix/Linux-Systems.

test:/fnGPMvvLCWqA
Tabelle 2: Eine Beispielzeile aus einer user-Datei

Um Einträge in dieser Datei zu erzeugen verwendet man das Utility htpasswd. Es generiert vor allem die verschlüsselten Passwörter in der zweiten Spalte der Datei. Die so generell zugelassenen Benutzer können nun noch unter Verwendung einer zweiten Datei (meist groups) zu Benutzergruppen zusammengefaßt werden.

Bei einer größeren Anzahl von Benutzern wird diese Art der Verwaltung jedoch schnell unhandlich und lästig. Bessere Verfahren arbeiten auf Basis einer Benutzerdatenbank. Nachfolgend soll nun diese Art der Benutzerverwaltung vorgestellt werden.

Datenbankgestützte Authentifizierung

Auch die datenbankgestützte Benutzer-Authentifizierung arbeitet mit den drei obigen Angaben:

Diese Daten sind nun aber nicht mehr in Dateien zu finden sondern werden mittels einer Datenbank - üblicherweise ein SQL-Server - verwaltet. Das Perl-Modul Apache::AuthDBI ist dann dafür verantwortlich mittels paßender Datenbankabfragen die vom Benutzer eingegebenen Daten mit den in der Datenbank gespeicherten Angaben abzugeleichen und Zugang zu gewähren oder abzulehnen.

Um die Datenbankverbindung aufzubauen bzw. die Abfragen zu stellen verwendet Apache::AuthDBI das Perl-Modul DBI.pm sowie die paßenden Datenbanktreiber (DBD's). Um also dieses Verfahren anwenden zu können müssen Sie zuerst für ein installiertes DBI/DBD-Gespann sorgen. Weitere Information zum Thema Datenbankzugriffe mit Perl finden Sie hier.

Zugangsschutz im Hypertext-Transfer-Protocol (http)

Das Wissen über dieses Kapitel ist für die Implementierung eines Zugangsschutzes nicht erforderlich. Ich fand es aber "nice to see" und habe es deshalb geschrieben. Falls Sie also keine Lust haben sich hier durchzuquälen dann lassen Sie's.

Im http-Protokoll wird der Zugangsschutz durch eine spezielle Rückantwort des Servers initiiert. Normale Rückantworten werden mit einem Statuscode 200 zurückübermittelt. Ein Statuscode 401 teilt dem Client mit, dass eine Authentifizierung erforderlich ist. Nachfolgend sehen Sie den Begin eines Zugriffs auf einen geschützten Bereich eines Webservers. Tabelle 3a zeigt die Anfrage (http://irgendwo.bw.schule.de/downloads/login) und Tabelle 3b die zugehörige Rückantwort.

GET /downloads/login HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.77 [en] (Win98; U)
Host: irgendwo.bw.schule.de
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: de,en
Accept-Charset: iso-8859-1,*,utf-8
Tabelle 3a: Die Clientanfrage im http-Protokoll

HTTP/1.1 401 Authorization Required
Date: Wed, 02 May 2001 11:09:00 GMT
Server: Apache/1.3.19 (Unix) mod_perl/1.25
WWW-Authenticate: Basic realm="Irgendwo Userbereich"
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
... weitere Infos ...

Tabelle 3b: Die Serverantwort im http-Protokoll mit Statuscode 401

Der Browser auf Client-Seite zeigt die bei der Serverantwort ebenfalls übermittelten HTML-Daten erst einmal nicht an sondern konfrontiert den Benutzer mit der Authentifizierungsabfrage (siehe Abb. 1). Nachdem der Benutzer seine Daten eingetragen hat, wird erneut eine Anfrage erzeugt. Dieses Mal beinhaltet die Anfrage aber eine Zeile mehr in der die Authentifizierungsdaten kodiert enthalten sind.

GET /downloads/login HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.77 [en] (Win98; U)
Host: irgendwo.bw.schule.de
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: de,en
Accept-Charset: iso-8859-1,*,utf-8
Authorization: Basic UmFwdW56ZWw6TGFzcyBkZWluIEhhYXIgaGVydW50ZXI=
Tabelle 4: Die Clientanfrage mit Übermittlung des Usernamens und des Passworts

Achtung: Die obige Codierung beinhaltet keinerlei Sicherheit gegen unbefugtes Abhören! Es handelt sich nicht um das Ergebnis einer Crypto-Funktion sondern nur um die Base64-kodierte Kombination aus Username und Passwort. Der dekodierte String (den jeder dekodieren kann) sieht im obigen Beispiel so aus: Rapunzel:Lass dein Haar herunter

Stimmen die Zugangsdaten, so liefert der Webserver die eigentlich angeforderten Informationen an den Client aus. Falls nicht reagiert er erneut mit einer 401-er Antwort. Bei Folgerequest in diesem oder untergeordneten Verzeichnissen sendet der Clientbrowser die Zugangsdaten jedesmal mit.

Die obigen Client-Anfragen wurden übrigens mit diesem kleinen Perl-Webserver "aufgenommen". Der Server läuft nach dem Start auf Port 8080 (damit kann er auch von normalen Usern auf einem Unix/Linux-System getestet werden). Beim ersten Aufruf wird eine Authentifizierung veranlaßt. Erst nach Angabe der richtigen Daten (s.o.) erhalten Sie eine Bestätigungsseite. Auf der Serverkonsole (lassen Sie den Server einfach im Vordergrund laufen) sehen Sie alle Daten die der Browser an den Server sendet.

Minimalversion einer Datenbank zur User-Authentifizierung

Um eine datenbankgestützte Benutzer-Authentifizierung durchführen zu können, benötigen Sie natürlich erst mal eine paßende Datenbank die alle notwendigen Daten enthält. In der Datenbank wird eine Tabelle benötigt die mindestens für die folgenden Aufgaben Felder:

Bei Verwendung des SQL-Servers MySQL könnte das so aussehen:

CREATE TABLE users (
username varchar(20) DEFAULT '' NOT NULL,
password varchar(20),
groupname varchar(20),
PRIMARY KEY (username)
);
Tabelle 5: SQL-CREATE-Befehl für Benutzertabelle

Natürlich darf die Tabelle auch einen anderen Namen haben, andere Feldbezeichner haben, noch beliebige weitere Felder beinhalten, ... . Damit besteht die Möglichkeit hier auch Tabellen zu verwenden die Sie ohnehin schon aus anderen verwaltungstechnischen Gründen angelegt haben. Auch eine komplete Online-Benutzerverwaltung ist eigentlich kein Problem.

Konfiguration des Apache-Webservers

Änderungen in der httpd.conf

Damit der Apache-Webserver die Authentifizierung über das Apache::AuthDBI-Modul kann, muß es beim Serverstart geladen werden. Dazu ist folgende Zeile in die httpd.conf einzufügen:

PerlModule Apache::AuthDBI

Inhalt der .htaccess-Datei

Ein Beispiel für die .htaccess-Datei sehen Sie in Tabelle 6.

AuthName "Geheimer Userbereich"
AuthType Basic

PerlAuthenHandler Apache::AuthDBI::authen
PerlAuthzHandler Apache::AuthDBI::authz

PerlSetVar Auth_DBI_encrypted off
PerlSetVar Auth_DBI_data_source dbi:mysql:webserver
PerlSetVar Auth_DBI_username mustermann
PerlSetVar Auth_DBI_password geheim
PerlSetVar Auth_DBI_pwd_table users
PerlSetVar Auth_DBI_uid_field username
PerlSetVar Auth_DBI_pwd_field password
PerlSetVar Auth_DBI_grp_field groupname

require group admin user

Tabelle 6: Die .htaccess-Datei für unser Beispiel

Die Direktiven bedeuten im Einzelnen folgendes:

AuthName "Geheimer Userbereich"
(Im RFC2617 "HTTP Authentication" auch als Realm bezeichnet) Legt die Bezeichnung des zugangsgeschützten Bereichs fest. Der Client kann anhand des Realm's auch Zugangskennungen cachen und bei Folgeaufrufen unaufgefordert mitschicken. Das Realm wird auch im Authentifizierungsfenster (s. Abb. 1) als Beschreibungstext angezeigt.
AuthType Basic
Legt das bei der Authentifizierung zu verwendende Schema (Protokoll) fest. Die Angabe "Basic" wurde bereits weiter oben erläutert. Außer "Basic" ist auch noch "Digest" im RFC2617 spezifiziert. "Digest" bietet eine bessere Sicherheitsstufe bei der Übertragung der Userdaten.
PerlAuthenHandler Apache::AuthDBI::authen
Legt fest welches Perl-Modul die Authentifizierung vornimmt (Authentification-Handler). Unter Authentifizierung wird die Anmeldung und damit eindeutige Identifizierung eines speziellen Users verstanden.
PerlAuthzHandler Apache::AuthDBI::authz
Legt fest welches Perl-Modul für die Authorisierung zuständig ist (Authorization-Handler). Die Authorisierung setzt eine vorab erfolgte Authentifizierung des Benutzers voraus. Solange der Benutzer also noch gar nicht angemeldet ist wird dieser Handler auch nicht aktiv. Unter Authorisierung versteht man die Rechtvergabe an den User anhand seiner Gruppenzugehörigkeit.
PerlSetVar Auth_DBI_encrypted off
Die Perl-Umgebungsvariable Auth_DBI_encrypted legt fest ob die Passwörter in der Datenbank in verschlüsselter oder unverschlüsselter Form vorliegen. Das bedeutet nicht, dass das Apache::AuthDBI-Modul die Verschlüsselung vornimmt! Der Authen-Handler benötigt diese Angabe um einen Vergleich zwischen übermitteltem und abgespeichertem Passwort vornehmen zu könnnen. Neben off kann noch on eingestellt werden. Welche Einstellung Sie hier verwenden ist von Fall zu Fall abzuwägen. Bei verschlüsselten Passwörtern haben Sie auch dann noch einigermaßen Sicherheit für die einzelnen Benutzer wenn aus irgendeinem Grund ein Angreifer an die Datenbank herangekommen ist. Allerdings haben Sie mehr Verwaltungsaufwand beim Erstellen der verschlüsselten Passwörter (das macht das Modul nämlich nicht). Für die Erstellung der verschlüsselten Passwörter verwenden Sie die crypt()-Funktion.
PerlSetVar Auth_DBI_data_source dbi:mysql:webserver
Die Perl Umgebungsvariable Auth_DBI_data_source legt die Datenbank fest in der die Benutzerdaten zu finden sind. Die Angabe ist analog der connect()-Methode des DBI-Moduls zu treffen (dbi ist immer anzugeben, mysql ist der für den Datenzugriff zu verwendende DBD-Treiber und ist natürlich vom real verwendeten SQL-Server abhängig, webserver ist der Name der Datenbank).
PerlSetVar Auth_DBI_username mustermann
SQL-Server Benutzername mit Zugriffsberechtigung auf die Datenbank und die Authentifizierungstabelle (s.a. Sicherheitshinweis in der nächsten Direktive).
PerlSetVar Auth_DBI_password geheim
SQL-Server-Passwort für den SQL-Server-Benutzer der vorherigen Direktive. Bei diesen beiden Direktiven sollte ein "ungefährlicher SQL-Server-Account" verwendet werden. Haben Sie nämlich aus Versehen die Rechte für Ihre .htaccess-Datei etwas zu großzügig eingestellt, können lokale und evtl. sogar Remote-Web-User die .htaccess einsehen. Mit den beiden Angaben besteht dann evtl. bereits die Möglichkeit den SQL-Server "aufzuräumen".
PerlSetVar Auth_DBI_pwd_table users
PerlSetVar Auth_DBI_uid_field username
PerlSetVar Auth_DBI_pwd_field password
PerlSetVar Auth_DBI_grp_field groupname
Diese vier Variablen teilen den beiden Handlern die Tabellen- und Feldbezeichnungen Ihrer Authentifizierungs-Datenbank mit. Auth_DBI_pwd_table gibt den Tabellennamen an, Auth_DBI_uid_field gibt den Bezeichner des Datenfelds mit dem Benutzernamen an, Auth_DBI_pwd_field gibt den Bezeichner des Datenfelds mit dem Benutzerpasswort an und Auth_DBI_grp_field gibt den Bezeichner für das Datenfeld mit der Benutzer-Gruppenzugehörigkeit an.
require group admin user
So ..., nachdem nun den Authen-Handlern alle Daten für einen Datenbankzugriff bekannt sind können sie ihre Arbeit erledigen. Hat ein Benutzer die richtigen Daten (Benutzerkennung und Passwort) übermittelt, so kann nun überprüft werden ob er überhaupt für diesen Bereich Zugriffsrechte hat. Es ist damit möglich einem Benutzer für manche Bereich Zugangsberechtigung zu erteilen während er an anderer Stelle trotz korrekter Benutzerdaten eben keinen Zugriff erhält. Im vorliegenden Beispiel haben alle Benutzer die zu einer der Gruppen admin oder user gehören eine gültige Zugangsberechtigung. Die Berechtigung kann auch auf Userebene vergeben werden indem die Zeile mit require user beginnt und anschließend einzelne Usernamen aufgelistet werden.

Sonst noch was ... ?

Aber sicher :-). Nach Inbetriebnahme des obigen Mechanismus stehen Ihnen natürlich noch etliche andere Möglichkeiten offen. Eine unvollständige Liste der Möglichkeiten sieht so aus:


 Lokal bzw. Remote-Zugriffe seit 2. Mai 2001