Kriminelle Authentifizierung PHP. HTTP Installieren des Schutzes auf einer Seite mithilfe von MySQL und PHP. Anwendung. Skriptquellen

Webmaster, die etwas von ihnen selbst geschriebenes als Website-Engine verwenden, werden es früher oder später leid, die Website zu aktualisieren, indem sie Dateien per FTP bearbeiten oder direkt mit der Datenbank arbeiten. Und dann beginnt das Schreiben von Verwaltungsskripten, mit denen Sie die Site verwalten können interaktiver Modus mit einem angenehmen Aussehen und machte den Update-Prozess endlich angenehmer.

Die erste Frage, die sich in diesem Fall meist stellt, ist die Frage der Genehmigung. Sie werden nicht jedem, der den Verwaltungsbereich auf der Website findet, die Möglichkeit geben, alles zu tun, was ihm in den Sinn kommt. Heute werden wir uns den Prozess des Schreibens einer einfachen Autorisierung ansehen.

Zunächst ein paar klärende Punkte. Zuerst schreiben wir in PHP, da dies heute die gebräuchlichste Sprache zum Schreiben von Website-Management-Systemen ist. Und zweitens bin ich persönlich gegen selbstgeschriebene Skripte, die für die Eingabe des Login-Passworts selbst verantwortlich sind. Erfinden wir also das Rad nicht neu, d.h. eigenes Autorisierungsprinzip, aber wir werden Standardfunktionen verwenden.

Daher verwenden wir die Standardauthentifizierung – ein Fenster zur Eingabe eines Passworts, das beispielsweise auf Rambler und vielen anderen Websites verwendet wird.

Die Möglichkeit, den geschützten Bereich zu betreten, bleibt während der gesamten Sitzung des Browserfensters bestehen, nach dem Schließen ist ein erneuter Zugang jedoch nur noch durch Eingabe Ihres Benutzernamens und Passworts möglich. Das heißt, dass Sie mit Ihrem Computer keine illegalen Handlungen in Ihrem Namen durchführen können. Was ist sonst noch gut an dieser Methode? Es akzeptiert keine Variablen von Servern Dritter und nach dreimaliger falscher Passworteingabe müssen Sie die Seite aktualisieren, was es schwierig macht, das System durch Raten zu hacken.

Und es sieht so aus:

Der vom Benutzer eingegebene Login wird in der Variablen $PHP_AUTH_USER gespeichert, das Passwort wird in $PHP_AUTH_PW gespeichert. Achten Sie übrigens darauf, das Vorhandensein eines Benutzerdatensatzes mit demselben Namen in der Datenbank zu überprüfen – dies ist ein kritischer Punkt, den es unbedingt zu berücksichtigen gilt. Wenn keine solche Prüfung erfolgt, führt dies zu katastrophalen Ergebnissen – $row wird gleich Null sein, d. h. durch Eingabe eines nicht vorhandenen Benutzernamens und eines leeren Passworts können Sie in die geschützte Zone gelangen.

Zwischen Anweisungen Header("HTTP/1.0 401 Unauthorized"); und exit() ; Wir fügen alles ein – von einem einfachen Satz, dass Sie nicht hierher kommen können, bis zu einem Vorschlag, irgendwohin zu gehen, zu fliegen, zu rennen, zu kriechen und so weiter. Ja, fast hätte ich es vergessen – die Variablen $dbhost, $dbuser, $dbpasswd und $dbname speichern Daten, die den Zugriff auf die Datenbank ermöglichen, sowie den Namen der Datenbank.

Ähnlicher Code muss in jede Seite des geschützten Bereichs eingefügt werden, beispielsweise über include .

Sie sind also geschützt. In meiner eigenen Person kann ich auch hinzufügen, dass mir persönlich die Passwortvergabe auf diese Weise sehr bequem und zuverlässig erscheint.

Wir erfahren, wie Sie eine einfache Benutzerauthentifizierung auf der Website durchführen. Die Website verfügt möglicherweise nur über Seiten für autorisierte Benutzer und diese funktionieren vollständig, wenn wir ihnen unseren Authentifizierungsblock hinzufügen. Um es zu erstellen, benötigen Sie eine MySQL-Datenbank. Es kann (mindestens) 5 Spalten umfassen, oder mehr, wenn Sie Informationen über Benutzer hinzufügen möchten. Nennen wir die Datenbank „Userauth“.

Erstellen wir darin die folgenden Felder: ID zum Zählen der Anzahl der Benutzer, UID für die eindeutige Identifikationsnummer des Benutzers, Benutzername für den Namen des Benutzers, E-Mail für seine Adresse Email und Passwort für das Passwort. Sie können Ihre vorhandene Datenbank verwenden, um den Benutzer zu autorisieren. Erstellen Sie einfach wie bei einer neuen Datenbank die folgende Tabelle darin.

MySQL-Code

CREATE TABLE „Benutzer“ („ID“ int (11) NICHT NULL AUTO_INCREMENT, „UID“ int (11) NICHT NULL, Text „Benutzername“ NICHT NULL, Text „E-Mail“ NICHT NULL, Text „Passwort“ NICHT NULL, PRIMÄRSCHLÜSSEL (`ID`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Nun erstellen wir die Datei „sql.php“. Es ist für die Verbindung zur Datenbank verantwortlich. Dieser Code erstellt zunächst Variablen für den Server und den Benutzer, wenn er eine Verbindung zum Server herstellt. Zweitens wird die Datenbank ausgewählt, in diesem Fall „USERAUTH“. Diese Datei muss in „log.php“ und „reg.php“ eingebunden sein, um auf die Datenbank zugreifen zu können.

PHP-Code

//Ihr MySQL-Benutzername$pass = "redere"; //Passwort $conn = mysql_connect ($server, $user, $pass); //Verbindung zum Server$db = mysql_select_db("userauth", $conn); //Datenbank auswählen if (!$db) ( //wenn keine Datenbank ausgewählt werden kann echo „Entschuldigung, Fehler:(/>“; //Zeigt Fehlermeldung an Ausfahrt(); //Ermöglicht die Ausführung anderer PHP-Skripte } ?>

Als nächstes folgt die Anmeldeseite, die „login.php“ heißen soll. Zunächst prüft es die eingegebenen Daten auf Fehler. Die Seite enthält Felder für Benutzername, Passwort, Senden-Button und Registrierungslink. Wenn der Benutzer auf die Schaltfläche „Anmelden“ klickt, wird das Formular durch den Code aus der Datei „log.php“ verarbeitet und anschließend angemeldet.

PHP-Code

0) { //wenn es Sitzungsfehler gibt$err = "

"; //Eine Tabelle foreach starten ($_SESSION["ERRMSG"] as $msg) ( //Jeden Fehler erkennen$err .= " "; //schreibe es in eine Variable) $err .= "
" . $msg . "
"; //den Tisch schließen unset ($_SESSION["ERRMSG"]); //Eine Sitzung löschen } ?> Login Formular
Benutzername
Passwort
Anmeldung


Dann schreiben wir ein Skript, um uns beim System anzumelden. Nennen wir es „log.php“. Es verfügt über eine Funktion zum Bereinigen der Eingabedaten von SQL-Injections, die Ihr Skript ruinieren können. Zweitens empfängt es die Formulardaten und prüft diese auf Richtigkeit. Wenn die Eingabedaten korrekt sind, leitet das Skript den Benutzer zur Seite der autorisierten Benutzer weiter. Wenn nicht, setzt es Fehler und leitet den Benutzer zur Anmeldeseite weiter.

PHP-Code

//Aufzeichnungssitzung starten function Fix($str) ( //Felder bereinigen $str = trim($str); if (get_magic_quotes_gpc()) ( $str = stripeslashes ($str); ) //Array zum Speichern von Fehlern$errflag = false ; //Fehlerflag $username = Fix($_POST["username"]); //Benutzername$password = Fix($_POST["password"]);//password ) //Passwortüberprüfung if ($password == "") ( $errmsg = "Passwort fehlt"; //Fehler $errflag = true; //hebt Flag im Fehlerfall) //Wenn das Fehlerflag gesetzt ist, wird zurück zum Registrierungsformular weitergeleitet //protokolliert Fehler session_write_close(); //Sitzung schließen //Umleitung Ausfahrt(); ) //Abfrage an die Datenbank$qry = "SELECT * FROM `users` WHERE `Username` = "$username" AND `Password` = "" . md5 ($password) . """; $result = mysql_query($qry); //überprüfen, ob die Anfrage erfolgreich war (ob Daten darauf vorhanden sind) if (mysql_num_rows ($result) == 1) ( while ($row = mysql_fetch_assoc ($result)) ( $_SESSION["UID"] = $row["UID"]; //Die UID aus der Datenbank abrufen und in die Sitzung einfügen$_SESSION["USERNAME"] = $username; // legt fest, ob der Benutzername mit dem Sitzungsnamen übereinstimmt session_write_close(); //Sitzung schließen header("location: member.php"); //Umleitung) ) else ( $_SESSION["ERRMSG"] = "Ungültiger Benutzername oder ungültiges Passwort"; //error session_write_close(); //Sitzung schließen header("location: login.php"); //Umleitung Ausfahrt(); ) ?>

Lassen Sie uns eine Registrierungsseite erstellen und sie „register.php“ nennen. Sie ähnelt der Anmeldeseite, verfügt jedoch über einige weitere Felder und anstelle eines Registrierungslinks gibt es einen Link zu login.php, falls der Benutzer bereits ein Konto hat.

PHP-Code

0) { //wenn es Sitzungsfehler gibt$err = "

"; //Beginn der Tabelle foreach ($_SESSION["ERRMSG"] as $msg) ( //setzt jeden Fehler$err .= " "; //schreibt sie in eine Variable) $err .= "
" . $msg . "
"; //Ende der Tabelle nicht gesetzt ($_SESSION["ERRMSG"]); //zerstört die Sitzung } ?> Anmeldeformular
Benutzername
Email
Passwort
Passwort wiederholen
Ich habe einen Account


Nun erstellen wir ein Registrierungsskript in der Datei „reg.php“. Es enthält „sql.php“, um eine Verbindung zur Datenbank herzustellen. Zum Löschen des Eingabefeldes wird die gleiche Funktion wie im Login-Skript verwendet. Variablen werden festgelegt mögliche Fehler. Als nächstes folgt eine Funktion zum Erstellen einer eindeutigen Kennung, die noch nie zuvor bereitgestellt wurde. Anschließend werden die Daten aus dem Anmeldeformular extrahiert und verifiziert. Dabei wird überprüft, ob die E-Mail-Adresse im richtigen Format vorliegt und das Passwort erneut korrekt eingegeben wird. Das Skript prüft dann, ob es in der Datenbank einen Benutzer mit demselben Namen gibt und meldet gegebenenfalls einen Fehler. Schließlich fügt der Code den Benutzer zur Datenbank hinzu.

PHP-Code

//Aufzeichnungssitzung starten function Fix($str) ( //Felder löschen $str = @trim($str); if (get_magic_quotes_gpc()) ( $str = stripeslashes ($str); ) gib mysql_real_escape_string zurück($str); ) $errmsg = array(); //Array zum Speichern von Fehlern$errflag = false ; //Fehlerflag $UID = "12323543534523453451465685454";//eindeutige ID $username = Fix($_POST["username"]); //Benutzername$email = $_POST["email"]; //E-Mail $password = Fix($_POST["password"]);//Passwort $rpassword = Fix($_POST["rpassword"]);//Passwort wiederholen //Benutzernamen prüfen if ($username == "") ( $errmsg = "Benutzername fehlt"; //error $errflag = true ; //hebt Flag im Fehlerfall) //E-Mail prüfen if(!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@+(\.+)*(\.(2,3 ))$", $email)) ( //muss dem Format entsprechen: [email protected]$errmsg = „Ungültige E-Mail“; //Fehler $errflag = true ; //hebt Flag im Fehlerfall } //Passwortüberprüfung if ($password == "") ( $errmsg = "Passwort fehlt"; //error $errflag = true ; //hebt Flag im Fehlerfall } //Passwort-Wiederholungsprüfung if ($rpassword == "") ( $errmsg = "Wiederholtes Passwort fehlt";//error $errflag = true ; //hebt Flag im Fehlerfall } //Passwortgültigkeit prüfen if (strcmp($password, $rpassword) != 0) ( $errmsg = "Passwörter stimmen nicht überein";//error $errflag = true ; //hebt Flag im Fehlerfall } //Überprüfen Sie, ob der Benutzername verfügbar ist if ($username != "") ( $qry = "SELECT * FROM `users` WHERE `Username` = "$username""; //Abfrage an MySQL $result = mysql_query ($qry); if ($result) ( if (mysql_num_rows ($result) > 0) ( //wenn der Name bereits verwendet wird$errmsg = „Benutzername wird bereits verwendet“; //Fehlermeldung$errflag = true; //hebt Flag im Fehlerfall) mysql_free_result($result); ) ) //Wenn die Daten nicht validiert sind, wird zurück zum Registrierungsformular weitergeleitet if ($errflag) ( $_SESSION["ERRMSG"] = $errmsg; //Fehlermeldung session_write_close(); //Sitzung schließen header("Speicherort: register.php"); //Umleitung Ausfahrt(); ) //Daten zur Datenbank hinzufügen$qry = "INSERT INTO `userauth`.`users`(`UID`, `Username`, `Email`, `Password`) VALUES("$UID","$username","$email","" . md5 ($password). """; $result = mysql_query($qry); //Überprüfen Sie, ob die Hinzufügungsanforderung erfolgreich war if ($result) ( echo „Danke für die Registrierung, „ .$username .“ Bitte melden Sie sich an Hier"; exit (); ) else ( die ("Fehler, schauen Sie später noch einmal nach"); ) ?>

Sie müssen außerdem ein Skript erstellen, um den Benutzer vom System abzumelden. Es beendet die Sitzung für den Benutzer mit der angegebenen eindeutigen ID und dem angegebenen Namen und leitet den Benutzer dann zur Anmeldeseite weiter.

PHP-Code

Schließlich kann das Skript „auth.php“ verwendet werden, um Seiten nur für autorisierte Benutzer zugänglich zu machen. Es überprüft die Anmeldedaten und ermöglicht dem Benutzer, wenn diese korrekt sind, das Durchsuchen der Seiten. Wenn nicht, wird er aufgefordert, sich anzumelden. Wenn jemand außerdem versucht, die Site zu hacken, indem er eine der Sitzungen erstellt, wird diese unterbrochen, wie im allgemeinen Fall.

PHP-Code

Eine der Bedingungen im obigen Code ist Gegenstand der Frage in .

Der folgende Code muss für autorisierte Benutzer in die Seite eingefügt werden. Er heißt beispielsweise „member.php“, Ihr Code kann jedoch beliebig heißen.

PHP-Code

Sie sind berechtigt, auf diese Seite zuzugreifen. Hinausgehen ( )

Die Benutzerauthentifizierung ist fertig!

Es ist möglich, die Funktion zu nutzen Header() Eine Nachricht senden "Authentifizierung erforderlich" Browser und zwingt ihn, ein Fenster zur Eingabe Ihres Benutzernamens und Passworts anzuzeigen. Sobald der Benutzer den Benutzernamen und das Kennwort ausgefüllt hat, wird der Link mit dem PHP-Skript erneut aufgerufen, wobei die vordefinierten Variablen PHP_AUTH_USER, PHP_AUTH_PW und AUTH_TYPE jeweils auf Benutzername, Kennwort und Authentifizierungstyp eingestellt sind. Diese vordefinierten Variablen werden in den Arrays $_SERVER und $HTTP_SERVER_VARS gespeichert. Beide Typen werden unterstützt: „Basic“ und „Digest“ (seit PHP 5.1.0). Einzelheiten siehe Funktion Header().

Ein Beispiel für ein Skriptfragment, das den Client dazu zwingt, sich anzumelden, um die Seite anzuzeigen:

Beispiel Nr. 1 Beispiel für eine einfache HTTP-Authentifizierung

if (!isset($_SERVER [ "PHP_AUTH_USER" ])) (
Header ( „WWW-Authenticate: Basic realm="My Realm"“);

Echo „Text gesendet wann
wenn der Benutzer auf die Schaltfläche „Abbrechen“ geklickt hat.
;
Ausfahrt;
) anders (
Echo
"

Hallo ( $_SERVER [ "PHP_AUTH_USER" ]).

" ;
Echo "

Sie haben Ihr Passwort eingegeben( $_SERVER [ "PHP_AUTH_PW" ]) .

" ;
}
?>

Beispiel Nr. 2 Digest-HTTP-Authentifizierungsbeispiel

Dies ist eine Beispielimplementierung eines einfachen Digest-HTTP-Authentifizierungsskripts. Einzelheiten finden Sie unter » RFC 2617.

$realm = "Verbotene Zone" ;

//Benutzer => Passwort
$users = array("admin" => "mypass" , "guest" => "guest" );

if (empty($_SERVER [ "PHP_AUTH_DIGEST" ])) (
header("HTTP/1.1 401 Unauthorized");
Header ( „WWW-Authenticate: Digest realm="“. $realm.
"",qop="auth",nonce="" . uniqid(). "",opaque="" . md5 ($realm). """ );

Sterben( „Text wird gesendet, wenn der Benutzer auf die Schaltfläche „Abbrechen“ klickt.“);
}

// Analysiere die Variable PHP_AUTH_DIGEST
if (!($data = http_digest_parse ($_SERVER [ "PHP_AUTH_DIGEST" ])) ||
!isset($users [ $data [ "username" ]]))
sterben( "Falschen Daten!");

// die richtige Antwort generieren
$A1 = md5 ($data [ "Benutzername" ] . :: . $realm . :: . $users [ $data [ "Benutzername" ]]);
$A2 = md5($_SERVER["REQUEST_METHOD"]. ":" . $data["uri" ]);
$valid_response = md5 ($A1 . :// ["qop"]. ::. $A2);

if ($data [ "response" ] != $valid_response )
sterben( "Falschen Daten!");

// ok, Login und Passwort sind korrekt
echo "Sie sind angemeldet als: " . $data["Benutzername"];

// HTTP-Authentifizierungs-Header-Analysefunktion
Funktion http_digest_parse ($txt)
{
// Schutz vor fehlenden Daten
$needed_parts = array("nonce" => 1 , "nc" => 1 , "cnonce" => 1 , "qop" => 1 , "username" => 1 , "uri" => 1 , "response" => 1 );
$data = array();
$keys = implode ("|" , array_keys ($needed_parts ));

Preg_match_all ("@(" . $keys . ")=(?:([\""])([^\2]+?)\2|([^\s,]+))@", $txt , $matches , PREG_SET_ORDER );

Foreach ($entspricht $m) (
$data [ $m [ 1 ]] = $m [ 3 ] ? $m [ 3 ] : $m [ 4 ];
unset($needed_parts [ $m [ 1 ]]);
}

$needed_parts zurückgeben? false: $data;
}
?>

Kommentar: Kompatibilitätshinweis

Seien Sie besonders vorsichtig, wenn Sie HTTP-Header angeben. Um maximale Kompatibilität mit möglichst vielen unterschiedlichen Clients zu gewährleisten, muss das Wort „Basic“ mit einem großen „B“ geschrieben werden, die Region (Realm) muss in doppelte (nicht einfache!) Anführungszeichen gesetzt werden und es muss genau ein Leerzeichen vorangestellt werden der Code 401 im Titel HTTP/1.0 401. Authentifizierungsparameter müssen durch Kommas getrennt werden, wie im Digest-Authentifizierungsbeispiel oben gezeigt.

Anstatt einfach die Variablen PHP_AUTH_USER und PHP_AUTH_PW auf dem Bildschirm anzuzeigen, müssen Sie möglicherweise überprüfen, ob sie korrekt sind. Verwenden Sie dazu eine Datenbankabfrage oder suchen Sie in einer DBM-Datei nach einem Benutzer.

Sie können die Bedienfunktionen des Internet Explorer-Browsers beobachten. Es ist sehr wählerisch, was die Parameter der übertragenen Header angeht. Der Titeltrick WWW-Authentifizieren vor dem Senden des Status HTTP/1.0 401 funktioniert bisher für ihn.

Um zu verhindern, dass jemand ein Skript schreibt, das das Passwort für eine Seite preisgibt, die externe Authentifizierung verwendet, werden die PHP_AUTH-Variablen nicht gesetzt, wenn die Seite externe Authentifizierung verwendet und auf den sicheren Modus eingestellt ist. Die Variable REMOTE_USER kann jedoch zur Authentifizierung eines extern authentifizierten Benutzers verwendet werden. Sie können also immer die Variable $_SERVER["REMOTE_USER"] verwenden.

Kommentar: Konfigurationshinweis

PHP verwendet Direktivenanzeige Authentifizierungstyp um anzugeben, ob eine externe Authentifizierung verwendet wird oder nicht.

Es ist zu beachten, dass all dies den Diebstahl von Passwörtern für Seiten, die eine Autorisierung erfordern, nicht durch jemanden verhindert, der Seiten ohne Autorisierung kontrolliert, die sich auf demselben Server befinden.

Sowohl Netscape Navigator als auch Internet Explorer löschen den Authentifizierungscache des aktuellen Fensters für einen bestimmten Bereich, wenn sie vom Server den Status 401 erhalten. Dies kann verwendet werden, um den Benutzer zu zwingen, sich abzumelden und das Dialogfeld mit Benutzername und Kennwort erneut anzuzeigen. Einige Entwickler nutzen dies, um Anmeldungen zeitlich zu begrenzen oder eine Abmeldeschaltfläche bereitzustellen.

Beispiel #3 Beispiel einer HTTP-Authentifizierung mit erzwungener Eingabe eines neuen Login/Passwort-Paares

Funktion Authenticate() (
Header ( „WWW-Authenticate: Basic realm="Authentifizierungssystem testen"“);
header("HTTP/1.0 401 Nicht autorisiert");
Echo „Sie müssen den richtigen Benutzernamen und das richtige Passwort eingeben, um Zugriff auf die Ressource zu erhalten \n“;
Ausfahrt;
}

if (!isset($_SERVER [ "PHP_AUTH_USER" ]) ||
($_POST [ "SeenBefore" ] == 1 && $_POST [ "OldAuth" ] == $_SERVER [ "PHP_AUTH_USER" ])) (
authentifizieren();
) anders (
Echo "

Willkommen zurück: ". htmlspecialchars($_SERVER["PHP_AUTH_USER"]) . "
" ;
Echo „Vorheriger Login:“. htmlspecialchars($_REQUEST["OldAuth"]);
Echo "

\N";
Echo "\N";
Echo ". htmlspecialchars($_SERVER["PHP_AUTH_USER"]) . "\" />\n" ;
Echo "\N";
Echo“

\N" ;
}
?>

Dieses Verhalten ist nicht durch Normen geregelt HTTP Basic-Authentifizierung, daher sollten Sie sich nicht darauf verlassen. Browsertests Luchs zeigte, dass Luchs Der Autorisierungscache wird nicht geleert, wenn vom Server der Status 401 empfangen wird. Wenn Sie nacheinander auf „Zurück“ und dann auf „Weiter“ klicken, können Sie eine solche Seite öffnen, sofern sich die erforderlichen Autorisierungsattribute nicht geändert haben. Der Benutzer kann jedoch die Taste drücken "_" um den Authentifizierungscache zu leeren.

Damit die HTTP-Authentifizierung auf einem IIS-Server mit einer CGI-Version von PHP ordnungsgemäß funktioniert, müssen Sie die IIS-Konfigurationseinstellung mit dem Namen „ Verzeichnissicherheit". Klicken Sie auf die Aufschrift " Bearbeiten" und stellen Sie die Option ein " Anonymer Zugriff", alle anderen Felder sollten deaktiviert bleiben.

Kommentar: Hinweis zu IIS:
Damit die HTTP-Authentifizierung in IIS korrekt funktioniert, muss in der PHP-Konfiguration die Option cgi.rfc2616_headers auf gesetzt sein 0 (Standardwert).

Kommentar:

Falls der abgesicherte Modus verwendet wird, wird die UID des aktuellen Skripts hinzugefügt Reich-Header-Teil WWW-Authentifizieren.

Das Einschränken des Zugriffs auf einen beliebigen Bereich der Website sieht normalerweise so aus
eintönig: Jeder Benutzer erhält einen Benutzernamen und ein Passwort oder er selbst
wählt sie aus und um den sicheren Teil der Website zu betreten, müssen sie eingegeben werden. Aus technischer Sicht, um das von ihnen verwendete Passwort zu überprüfen
verschiedene Methoden. Zur Eingabe Ihres Logins und Passworts können Sie ein HTML-Formular verwenden.
In diesem Fall wird das Passwort in der POST-Anfrage im Klartext an den Server gesendet.
Dies ist nach Möglichkeit nicht akzeptabel, wenn der Benutzer lokal ist
mit einem Schnüffler. Um dieses Problem zu lösen, wurde eine Methode erfunden
Authentifizierung mittels Hashes, bei dem das Passwort nicht übertragen wird, sondern
Je nach Passwort wird einmalig ein Hash-String übertragen
Parameter und möglicherweise von einigen anderen Parametern. Diese Methode ist auch
wird als Challenge/Response bezeichnet, da bei der Verwendung der Client
empfängt eine Anfrage mit einem einmaligen Parameter und sendet eine Antwort mit dem Hash. Auf der HTTP 1.1-Protokollebene erfolgt die Authentifizierung mithilfe von
Basic, das nicht besser ist als die Verwendung eines HTML-Formulars, und Digest, das
wir werden es uns im Detail ansehen.

Bei Verwendung der Digest-Methode, wie bereits erwähnt, das Passwort
wird nicht übertragen und kann nicht erschnüffelt werden, aber es gibt noch eine andere Seite
Probleme. Um das Passwort zu überprüfen, muss der Server berechnen
Antwort und vergleichen Sie sie mit der Client-Antwort, daher muss der Server
Speichern Sie das Passwort oder die davon abhängigen Daten, die für erforderlich sind
Bestehen der Authentifizierung. Daraus folgt, dass eine Person, die Rechte erhalten hat
um Konten zu lesen (z. B. mithilfe von SQL-Injection), können Sie diese abrufen
Zugriff auf Seiten, die durch die Digest-Methode geschützt sind. Bei Verwendung der Methode
Grundsätzlich ist es möglich, Hashes anstelle von Passwörtern zu speichern, wodurch Sie keine Rechte erhöhen können.
Nachdem wir diese Hashes gelesen haben (wir werden weiter unten sehen, dass Digest auch Hashes speichern kann,
aber so, dass ihr Wissen ausreicht, um die Antwort zu berechnen). Somit stehen wir vor einem Dilemma: Entweder wird unser Passwort ausgespäht,
oder sie bekommen es über eine Web-Schwachstelle, die bestimmt jemand finden wird,
denn wer sucht, wird immer finden. Es gibt eine Authentifizierungsmethode ohne
Diese beiden Nachteile sind die Authentifizierungsmethode mit öffentlichem Schlüssel:
Um die Verifizierung zu bestehen, benötigen Sie einen öffentlichen Schlüssel, und um die Verifizierung zu bestehen, benötigen Sie einen geheimen Schlüssel.
HTTP 1.1 bietet eine solche Methode jedoch nicht. RFC 2069
empfiehlt die Verwendung von SSL, wenn Sicherheit so wichtig ist. Lediglich die Übertragung des Passwortes ist geschützt, die Inhalte werden also nicht verschlüsselt
dass es keinen Sinn macht, mit dieser Methode Ressourcen zu schützen, woher der Benutzer kommt
erhält geheime Informationen. Sie erfordern SSL. Und es macht Sinn
Schützen Sie beispielsweise ein Forum oder das Hochladen von Inhalten auf eine Website. Wenn das Hosting also kein SSL unterstützt, muss die Authentifizierung erfolgen
Aus Sicherheitsgründen verwenden wir Digest. Apache stellt das Modul mod_digest bereit. Um es zu benutzen
in der config (bzw. in .htaccess) schreiben wir:

AuthType-Digest
AuthUserFile<файл>
AuthName<название защищаемой области>
Erfordert valid_user

Benutzerdateien werden vom Dienstprogramm erstellt
htdigest. Es gab einmal Berichte über mod_digest, dass es angreifbar sei
Möglicherweise treten dort noch andere Probleme auf. Außerdem, wann
Ich habe versucht, es zu Hause zu verwenden, aber es ist eine Fehlermeldung aufgetreten
500 Interner Serverfehler. Außerdem, wenn das Hinzufügen von Konten erfolgen soll
automatisch, und es sollten viele davon sein, das sollten sie auch
nicht in der Apache-Konfiguration gespeichert, sondern in MySQL. Lösung -
Verwenden Sie PHP. PHP bietet hierfür keine integrierte Unterstützung
Methode, daher muss sie implementiert werden. Dazu müssen Sie lernen
diese Methode im Detail. Lassen Sie mich sofort darauf hinweisen, dass die Informationen in diesem Artikel
Die Implementierung funktioniert nur auf Apache, da voller Zugriff auf Header
request (Apache_request_headers-Funktion) funktioniert nur in Apache, aber weiter
ist möglicherweise auf anderen Servern nicht verfügbar. Wir müssen nur lesen
Autorisierungsheader.

Beschreibung der Methode

Die vollständige Beschreibung der Methode finden Sie in RFC 2069
Kurz gesagt, die Methode funktioniert so. Wenn der Server eine Anfrage bezüglich des geschützten Bereichs erhält,
Es wird der Fehler 401 „Autorisierung erforderlich“ und der Anforderungsheader ausgegeben
Authentifizierung dieser Art:

WWW-Authenticate: Digest realm="sicherer Bereich", nonce="123456123456"

Realm ist der Name des geschützten Bereichs und Nonce ist eine einmalige Verwendung
Bedeutung. Es gibt auch optionale Parameter, die wir besprechen werden
wir werden nicht. Der Client wiederholt die Anfrage und fügt einen Header wie diesen hinzu:

Autorisierung: Digest realm="sicherer Bereich", Benutzername="123", uri="/index.php", nonce="123456123456", Response="1234567890abcdef1234567890abcdef"

Der URI-Parameter muss mit dem URI in der Anfrage übereinstimmen, und die Antwort stimmt
die Antwort, die wie folgt berechnet wird:

Antwort = H(H(A1) + „:“ + Nonce + „:“ + H(A2))
H – Hash-Funktion, Standard MD5
A1 = Login + „:“ + Bereich + „:“ + Passwort
A2 = Anforderungsmethode + ":" + URI
Die Anforderungsmethode ist GET, POST usw.

Wie wir sehen, ist A1 weder von der Anfrage noch vom Einmaligen abhängig
Werte, sodass der Server kein Passwort speichern kann, sondern
H(A1). Genau so ist es in mod_digest in Apache implementiert.
Für den Auftraggeber genügen jedoch die gleichen Daten. Der Angreifer hat erhalten
Dieser Hash kann die Antwort mithilfe der oben genannten Formeln berechnen und
Generieren Sie mit dem Programm beispielsweise eine HTTP-Anfrage
AccessDriver und sein HTTP-Tool
Debugger. Dieser Vorgang wird im Folgenden detaillierter dargestellt. Der Server sollte prüfen, ob der Wert eine Nonce ist
diejenige, die dem Kunden zuvor ausgestellt wurde, und ob sie veraltet ist.
Wenn die Antwort mit dem Nonce-Parameter übereinstimmt, aber mit dem Wert dieses Parameters
nicht relevant, die oben beschriebene Antwort mit Code 401 wird nur ausgegeben, weil
Der Unterschied besteht darin, dass der Parameter zum WWW-Authenticate-Header hinzugefügt wird
stale=true, was anzeigt, dass der Zugriff nur aus diesem Grund verweigert wird,
und sollte es erneut versuchen, ohne den Benutzer zur Eingabe eines neuen Passworts aufzufordern. Das ist meiner Meinung nach unpraktisch, denn wenn eine solche Situation eintritt
Wenn der Client eine POST- oder PUT-Anfrage mit einem großen Datenblock stellt, muss er dies tun
alle Daten zweimal übertragen. Um dies zu vermeiden, sieht die Norm vor
Authentication-Info-Header, auf den der Server antworten kann
erfolgreiche Anfrage, dem Client die nächste Nonce mitzuteilen.
Die Syntax ist dieselbe wie bei WWW-Authenticate, außer dass die Nonce
wird durch nextnonce ersetzt. Allerdings, nach den Ergebnissen meiner zu urteilen
Experimente ignoriert Opera diesen Header. Eine andere Lösung: gem
RFC 2068 (HTTP/1.1): Der Server antwortet möglicherweise, bevor die Anfrage abgeschlossen ist.
damit der Client unnötige Datenübertragungen unterbricht, in Apache+PHP jedoch
ist nicht implementiert, da die Ausführung des Skripts erst danach beginnt
wie Apache die Anfrage vollständig empfängt und analysiert.

Speichern von Daten zwischen Anfragen

Es gibt einen subtilen Punkt bei der Implementierung der Challenge/Response-Methode in PHP.
Ein einmaliger Parameter wird generiert und in einer Antwort an den Client ausgegeben
wird in einer anderen Sitzung des Skripts überprüft.
Das heißt, es muss von einem Skriptaufruf zum anderen gespeichert werden, und dafür müssen Sie es tun
Verwenden Sie Dateien oder Datenbanken. Mein Beispiel verwendet Dateien mit dem Namen
entsprechenden Einmalwerten und die Dateien selbst enthalten
IP-Adressen der Clients, an die sie ausgegeben werden. Die Sammlung ist im Beispiel nicht implementiert
Müll: Sie müssen alte Dateien regelmäßig löschen.

Code-Analyse

Dieses Skript überprüft nur das Passwort und funktioniert unabhängig davon
Anmeldung Abhängig vom Erfolg der Prüfung werden einfache Antworten gegeben.

$realm = "sicherer Bereich"; // Name des Schutzgebiets
$pass = "pass"; // Passwort
$fileprefix = "./"; // Pfad für Tag-Dateien, der die Gültigkeit der Nonce angibt

/* Erstellen wir einen einmaligen Parameter wie in RFC2069 empfohlen, obwohl dies auch anders möglich ist. Der Parameter sollte, wie empfohlen, von der Client-Adresse, der aktuellen Uhrzeit und der geheimen Zeichenfolge abhängen. */
$nonce = md5($_SERVER["REMOTE_ADDR"] . :: . time() . ":MyCooolPrivateKey");

// Holen Sie sich die Header
$headers = apache_request_headers();

// Das Flag, das wir nach erfolgreicher Überprüfung auf TRUE setzen
$auth_success = FALSE;
$stale = "";

// Wenn kein Autorisierungsheader vorhanden ist, gibt es nichts zu überprüfen
if (isset($headers["Authorization"]))
{
$authorization = $headers["Authorization"];

/* Lassen Sie uns den Titel mit einem regulären Ausdruck analysieren. Der Titel enthält das Wort „Digest“ und eine Liste
Parameter der Form param="value" oder param=value, getrennt durch Kommas. Dieser reguläre Ausdruck entspricht einem solchen Parameter.
*/
preg_match_all("/(,|\s|^)(\w+)=("([^"]*)"|([\w\d]*))(,|$)/",
$authorization, $matches, PREG_SET_ORDER);

/* Zur Vereinfachung der weiteren Verarbeitung erstellen wir nun ein Array, dessen Schlüssel die Namen der Parameter und die Werte der Array-Elemente sind
Parameterwerte.
*/
$auth_params = Array();
für ($i = 0; $i< count($matches); $i++)
{
$match = $matches[$i];

/* Der Name steht immer in der zweiten Klammergruppe, je nachdem, ob er in Anführungszeichen steht oder nicht, ist dies möglich
in der 4. oder 5. Gruppe sein. Für Gruppen von Klammern, die fallen
zu einem nicht implementierten Zweig, einer leeren Zeichenfolge im Array,
Sie können die Werte also einfach addieren.
*/
$auth_params[$match] = $match . $match;
}

/* Berechnen wir die Antwort, die entspricht
das vom Benutzer eingegebene Login, unser Passwort und ein vom Benutzer übergebener einmaliger Parameter.
*/
$a1 = $auth_params["Benutzername"] . :: . $auth_params["realm"] . :: . $pass;
$a2 = $_SERVER["REQUEST_METHOD"] . :: . $_SERVER["REQUEST_URI"];
$resp = md5(md5($a1) . :: . $auth_params["nonce"] . :: . md5($a2));

// Schauen wir uns die Antwort an.
if ($resp == $auth_params["response"])
{
//
Überprüfung der Relevanz des Einmalparameters
$fn = $fileprefix . $auth_params["nonce"];
if (@file_get_contents($fn) == $_SERVER["REMOTE_ADDR"])
{
unlink($fn); //
Diese Option ist nicht mehr relevant
$auth_success = TRUE; //
Authentifizierung bestanden
) anders
{
// Einmalige Parameter sind irrelevant
$stale = ", stale=true";
}
}
}

if ($auth_success)
{
drucken(" Digest-Authentifizierungstest

print("Erfolgreich authentifiziert\n");
var_dump($auth_params);

drucken("");

) anders
{
file_put_contents($fileprefix . $nonce, $_SERVER["REMOTE_ADDR"]);

$proto = $_SERVER["SERVER_PROTOCOL"];
Header("$proto 401 nicht autorisiert");
Header("WWW-Authenticate: Digest realm=\"$realm\", nonce=\"$nonce\"$stale");

drucken(" Digest-Authentifizierungstest

");
print("Sie müssen sich mit der Digest-Methode authentifizieren");
drucken("


");
}

Bestehen der Digest-Authentifizierung mit bekanntem H(A1)

Ich zeige Ihnen anhand eines Beispiels, wie Sie die Verifizierung bestehen, wenn das Passwort unbekannt ist.
aber H(A1) ist bekannt. Dafür benötigen Sie, wie bereits erwähnt
AccessDriver. Ich werde Hash-Berechnungen durchführen, indem ich über die Befehlszeile aufrufe
PHP-CLI. Lassen Sie die geschützte Seite unter liegen
http://mrblack.local/auth1.php und der H(A1)-Hash ist „a8fb5b2d780a7bf0782207a51a013f04“.

Öffnen Sie AccessDriver->Tools->HTTP Debugger und geben Sie die Adresse ein
„http://mrblack.local/auth1.php“. Klicken Sie auf „Verbinden“. Wir bekommen:

HTTP-Header = HTTP/1.1 401-Autorisierung erforderlich
HTTP-Header = Datum: Montag, 04. Juli 2005 08:09:17 GMT
HTTP-Header = Server: Apache/1.3.31 (Win32) PHP/5.0.2
HTTP-Header = X-Powered-By: PHP/5.0.2
HTTP-Header = WWW-Authenticate: Digest realm="sicherer Bereich", nonce="5925bea78552224abda11bfe318a8a03"
HTTP-Header = Verbindung: schließen
HTTP-Header = Inhaltstyp: text/html

Öffnen Sie die Konsole, gehen Sie in den Ordner mit PHP und geben Sie den folgenden Befehl ein:

php -r "print md5("a8fb5b2d780a7bf0782207a51a013f04:
: ".md5("GET:http://mrblack.local/auth1.php"));"

Wir erhalten die erforderliche Digest-Antwort: c6d0af0db239d75c
3f59640a4896d096
Aktivieren Sie nun in AccessDriver das Kontrollkästchen „Header-Daten“ und kopieren Sie es in das angezeigte Feld
Feldüberschriften, die in der vorherigen Anfrage gesendet wurden, und fügen sie hinzu
Genehmigung. Folgendes passiert:

GET http://mrblack.local/auth1.php HTTP/1.1
Akzeptieren: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Akzeptierte Sprache: en-us,en;q=0.5
User-Agent: Mozilla-kompatibel
Host: mrblack.local
Pragma: kein Cache
Autorisierung: Digest username="mrblack", realm="secure area", nonce="5925bea78552224ab
da11bfe318a8a03", uri="http://mrblack.local/auth1.php", Response="c6d0af0db239d75c3f59
640a4896d096"

Klicken Sie auf „Verbinden“. Wir erhalten das Ergebnis:



Zum Senden einer „Authentifizierung erforderlich“-Meldung an den Client-Browser, die wiederum dazu führt, dass ein Dialogfeld zur Eingabe des Benutzernamens und Passworts angezeigt wird. Nachdem der Client seinen Namen und sein Passwort eingegeben hat, wird das Skript erneut aufgerufen, jedoch mit den vordefinierten Variablen PHP_AUTH_USER, PHP_AUTH_PW und AUTH_TYPE, die jeweils den Benutzernamen, das Passwort und den Authentifizierungstyp enthalten. Diese Variablen finden Sie im Array $_SERVER und $HTTP_SERVER_VARS. Derzeit wird nur die „Basic“-Authentifizierung unterstützt. Sie können auch eine detailliertere Beschreibung der Funktion lesen Header() .

Ein Beispiel für ein Skriptfragment, das den Client dazu zwingt, sich anzumelden, um die Seite anzuzeigen:

Beispiel für HTTP-Authentifizierung

if (!isset($_SERVER [ "PHP_AUTH_USER" ])) (
Header ( „WWW-Authenticate: Basic realm="My Realm"“);

Echo „Text gesendet wann
wenn der Benutzer auf die Schaltfläche „Abbrechen“ geklickt hat.
;
Ausfahrt;
) anders (
Echo
"

Hallo ($_SERVER["PHP_AUTH_USER"]).

"
;
Echo "

Sie haben Ihr Passwort eingegeben ($_SERVER["PHP_AUTH_PW"]).

"
;
}
?>

Kompatibilitätshinweis: Seien Sie besonders vorsichtig, wenn Sie HTTP-Header angeben. Um eine maximale Kompatibilität mit möglichst vielen unterschiedlichen Clients zu gewährleisten, muss das Wort „Basic“ mit einem großen „B“ geschrieben werden, die Region (Realm) muss in doppelte Anführungszeichen (keine einfachen!) eingeschlossen werden und es muss genau ein Leerzeichen vorangestellt werden der Code 401 im Titel HTTP/1.0 401 .

Anstatt einfach die Variablen PHP_AUTH_USER und PHP_AUTH_PW auf dem Bildschirm anzuzeigen, müssen Sie möglicherweise überprüfen, ob sie korrekt sind. Verwenden Sie dazu eine Datenbankabfrage oder suchen Sie in einer DBM-Datei nach einem Benutzer.

Sie können die Bedienfunktionen des Internet Explorer-Browsers beobachten. Es ist sehr wählerisch, was die Parameter der übertragenen Header angeht. Angabe eines Titels WWW-Authentifizieren vor dem Senden des HTTP/1.0 401-Status ist ein kleiner Trick.

Um zu verhindern, dass jemand ein Skript schreibt, das das Passwort für eine Seite preisgibt, die externe Authentifizierung verwendet, werden ab PHP 4.3.0 die PHP_AUTH-Variablen nicht gesetzt, wenn die Seite externe Authentifizierung verwendet und auf den sicheren Modus eingestellt ist. Die Variable REMOTE_USER kann jedoch zur Authentifizierung eines extern authentifizierten Benutzers verwendet werden. Sie können also immer die Variable $_SERVER["REMOTE_USER"] verwenden.

Notiz: PHP verwendet die AuthType-Direktive, um anzugeben, ob externe Authentifizierung verwendet wird oder nicht.

Es ist zu beachten, dass all dies den Diebstahl von Passwörtern für Seiten, die eine Autorisierung erfordern, nicht durch jemanden verhindert, der Seiten ohne Autorisierung kontrolliert, die sich auf demselben Server befinden.

Sowohl Netscape Navigator als auch Internet Explorer löschen den Authentifizierungscache des aktuellen Fensters für einen bestimmten Bereich, wenn sie vom Server empfangen werden. Dies kann verwendet werden, um den Benutzer zu zwingen, sich abzumelden und das Dialogfeld mit Benutzername und Passwort erneut anzuzeigen. Einige Entwickler nutzen dies, um Anmeldungen zeitlich zu begrenzen oder eine Abmeldeschaltfläche bereitzustellen.

Beispiel einer HTTP-Authentifizierung mit erzwungener Eingabe eines neuen Login/Passwort-Paares

Funktion Authenticate() (
Header ( „WWW-Authenticate: Basic realm="Authentifizierungssystem testen"“);
header("HTTP/1.0 401 Nicht autorisiert");
Echo „Sie müssen den richtigen Benutzernamen und das richtige Passwort eingeben, um Zugriff auf die Ressource zu erhalten \n“;
Ausfahrt;
}

If (!isset($_SERVER [ "PHP_AUTH_USER" ]) ||
($_POST [ "SeenBefore" ] == 1 && $_POST [ "OldAuth" ] == $_SERVER [ "PHP_AUTH_USER" ])) (
authentifizieren ();
}
anders(
Echo
"

Willkommen: ($_SERVER["PHP_AUTH_USER"])
" ;
Echo „Vorherige Anmeldung: ($_REQUEST[“OldAuth“])“;
Echo "

\N";
Echo "\N";
Echo "\N";
Echo "\N";
Echo“

\N" ;
}
?>

Dieses Verhalten wird nicht durch die HTTP-Basic-Authentifizierungsstandards geregelt, daher sollten Sie sich nicht darauf verlassen. Tests haben gezeigt, dass der Lynx-Browser den Autorisierungscache nicht löscht, wenn er einen 401-Status vom Server erhält. Durch Klicken nacheinander auf „Zurück“ und dann auf „Weiter“ ist es möglich, eine solche Seite zu öffnen, sofern die erforderliche Autorisierung vorliegt Attribute haben sich nicht geändert. Der Benutzer kann jedoch die Taste „_“ drücken, um den Authentifizierungscache zu leeren.

Es ist außerdem zu beachten, dass die HTTP-Authentifizierung vor PHP 4.3.3 aufgrund einiger IIS-Einschränkungen nicht auf Servern funktionierte, auf denen Microsoft IIS ausgeführt wurde, wenn PHP als CGI-Modul installiert war. Damit es in PHP 4.3.3+ ordnungsgemäß funktioniert, müssen Sie die IIS-Konfigurationseinstellung namens „Verzeichnissicherheit“ bearbeiten. Klicken Sie auf die Aufschrift „Bearbeiten“ und stellen Sie die Option „Anonymer Zugriff“ ein, alle anderen Felder sollten deaktiviert bleiben.

Eine weitere Einschränkung, wenn Sie IIS über ISAPI verwenden: Die PHP_AUTH_*-Variablen sind nicht definiert, aber gleichzeitig ist die HTTP_AUTHORIZATION-Variable verfügbar. Beispielcode, den Sie verwenden könnten: list($user, $pw) = explosion(":", base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)));

Hinweis zu IIS:: Damit die HTTP-Authentifizierung in IIS ordnungsgemäß funktioniert, muss die Option cgi.rfc2616_headers in der PHP-Konfiguration auf 0 (Standardwert) gesetzt sein.

Aufmerksamkeit: Falls der geschützte Modus verwendet wird, wird die UID des aktuellen Skripts zum Realm-Teil des WWW-Authenticate-Headers hinzugefügt.



<<< Назад Inhalt Weiterleiten >>>
Wenn Sie weitere Fragen haben oder etwas nicht klar ist, willkommen bei uns