it-swarm.com.de

HTTP-Authentifizierung über PHP

Was ist der richtige Weg, um sich vom HTTP-Authentifizierungs-Ordner abzumelden?

Es gibt Problemumgehungen, die dies erreichen können, aber sie sind potenziell gefährlich, da sie fehlerhaft sein können oder in bestimmten Situationen/Browsern nicht funktionieren. Deshalb suche ich nach einer korrekten und sauberen Lösung.

147
Josef Sábl

Mu. Es gibt keinen korrekten Weg, auch nicht einen Browser, der konsistent ist.

Dies ist ein Problem, das aus der HTTP-Spezifikation (Abschnitt 15.6) stammt:

Bestehende HTTP-Clients und Benutzeragenten behalten in der Regel die Authentifizierung bei Informationen auf unbestimmte Zeit. HTTP/1.1. bietet keine Methode für eine Server an die Clients, diese zwischengespeicherten Anmeldeinformationen zu verwerfen.

Auf der anderen Seite, Abschnitt 10.4.2 sagt:

Wenn die Anforderung bereits Berechtigungsnachweise enthält, wird 401 Antwort zeigt an, dass die Autorisierung für diese .__ abgelehnt wurde. Referenzen. Wenn die 401-Antwort dieselbe Herausforderung wie das .__ enthält. Vorherige Antwort, und der Benutzeragent hat bereits versucht Authentifizierung mindestens einmal, dann sollte der Benutzer angezeigt werden Entität, die in der Antwort angegeben wurde, da diese Entität einschlägige Diagnoseinformationen enthalten.

Mit anderen Worten: Sie können die Login-Box möglicherweise erneut anzeigen (wie @Karsten sagt), , aber der Browser muss Ihre Anfrage nicht berücksichtigen auf dieses (mis) merkmal zu viel.

102
Piskvor

Methode, die in Safari gut funktioniert. Funktioniert auch in Firefox und Opera, jedoch mit einer Warnung.

Location: http://[email protected]/

Dadurch wird der Browser angewiesen, die URL mit einem neuen Benutzernamen zu öffnen und den vorherigen zu überschreiben.

57
Kornel

Die einfache Antwort ist, dass Sie sich nicht zuverlässig von der http-Authentifizierung abmelden können.

Die lange Antwort:
Http-auth (wie der Rest der HTTP-Spezifikation) soll zustandslos sein. "Eingeloggt" oder "Abgemeldet" zu sein, ist also nicht wirklich sinnvoll. Der beste Weg, um es zu sehen, ist zu fragen, für jede HTTP-Anfrage (und denken Sie daran, dass das Laden einer Seite normalerweise aus mehreren Anfragen besteht): "Können Sie tun, was Sie möchten?". Der Server sieht jede Anforderung als neu an und ist nicht mit früheren Anfragen verknüpft.

Browser haben sich dafür entschieden, sich die Anmeldeinformationen zu merken, die Sie ihnen auf der ersten 401 mitgeteilt haben, und sie erneut zu senden, ohne die ausdrückliche Erlaubnis des Benutzers für nachfolgende Anforderungen. Dies ist ein Versuch, dem Benutzer das "angemeldete/abgemeldete" Modell zu geben, das er erwartet, aber es ist ein reiner Verlust. Es ist der Browser , der diese Persistenz des Staates simuliert. Der Webserver weiß nichts davon.

"Abmelden" ist also im Kontext von http-auth eine vom Browser bereitgestellte Simulation und somit außerhalb der Autorität des Servers.

Ja, es gibt kludges. Aber sie brechen die REST-Fähigkeit (wenn das für Sie von Wert ist) und sie sind unzuverlässig.

Wenn Sie für Ihre Site-Authentifizierung unbedingt ein an-/abgemeldetes Modell benötigen, ist die beste Wette ein Tracking-Cookie, dessen Status auf irgendeine Art auf dem Server gespeichert ist (MySQL, SQLite, Flatfile usw.). Dies erfordert, dass alle Anforderungen beispielsweise mit PHP ausgewertet werden.

43
Jonathan Hanson

Problemumgehung

Sie können dies mit Javascript tun:

<html><head>
<script type="text/javascript">
function logout() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
          xmlhttp = new XMLHttpRequest();
    }
    // code for IE
    else if (window.ActiveXObject) {
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (window.ActiveXObject) {
      // IE clear HTTP Authentication
      document.execCommand("ClearAuthenticationCache");
      window.location.href='/where/to/redirect';
    } else {
        xmlhttp.open("GET", '/path/that/will/return/200/OK', true, "logout", "logout");
        xmlhttp.send("");
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {window.location.href='/where/to/redirect';}
        }


    }


    return false;
}
</script>
</head>
<body>
<a href="#" onclick="logout();">Log out</a>
</body>
</html>

Was oben gemacht wird, ist:

  • für IE - einfach den Auth-Cache löschen und irgendwo umleiten 

  • für andere Browser - Senden Sie einen XMLHttpRequest mit "Logout" -Anmeldename und Kennwort hinter den Kulissen. Wir müssen es an einen Pfad senden, der 200 OK für diese Anforderung zurückgibt (d. H. Es sollte keine HTTP-Authentifizierung erforderlich sein).

Ersetzen Sie '/where/to/redirect' durch einen Pfad, zu dem nach dem Abmelden umgeleitet werden soll, und ersetzen Sie '/path/that/will/return/200/OK' durch einen Pfad auf Ihrer Site, der 200 OK zurückgibt.

26
Anton Mochalin

Workaround (keine saubere, nette (oder sogar funktionierende! Siehe Kommentar) Lösung):

Deaktivieren Sie einmal seine Anmeldeinformationen.

Sie können Ihre HTTP-Authentifizierungslogik nach PHP verschieben, indem Sie die entsprechenden Header senden (falls nicht angemeldet):

Header('WWW-Authenticate: Basic realm="protected area"');
Header('HTTP/1.0 401 Unauthorized');

Und die Eingabe analysieren mit:

$_SERVER['PHP_AUTH_USER'] // httpauth-user
$_SERVER['PHP_AUTH_PW']   // httpauth-password

Es sollte also trivial sein, seine Referenzen einmal zu deaktivieren.

13
Karsten

Melden Sie sich in zwei Schritten von HTTP Basic Auth ab

Angenommen, ich habe ein HTTP-Basic-Auth-Realm mit dem Namen "Password protected" und Bob ist angemeldet. Zum Abmelden stelle ich 2 AJAX -Anfragen vor:

  1. Rufen Sie das Skript/logout_step1 auf. Er fügt den .htusers einen zufälligen temporären Benutzer hinzu und antwortet mit seinem Login und Passwort.
  2. Zugriffsskript/logout_step2 authentifiziert mit dem Login und Kennwort des temporären Benutzers . Das Skript löscht den temporären Benutzer und fügt diesen Header in der Antwort hinzu: WWW-Authenticate: Basic realm="Password protected"

An diesem Punkt hat der Browser die Anmeldeinformationen von Bob vergessen.

7
Vlad GURDIGA

Meine Lösung für das Problem ist folgende. Die Funktion http_digest_parse, $realm und $users finden Sie im zweiten Beispiel dieser Seite: http://php.net/manual/de/features.http-auth.php

session_start();

function LogOut() {
  session_destroy();
  session_unset($_SESSION['session_id']);
  session_unset($_SESSION['logged']);

  header("Location: /", TRUE, 301);   
}

function Login(){

  global $realm;

  if (empty($_SESSION['session_id'])) {
    session_regenerate_id();
    $_SESSION['session_id'] = session_id();
  }

  if (!IsAuthenticated()) {  
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Digest realm="'.$realm.
   '",qop="auth",nonce="'.$_SESSION['session_id'].'",opaque="'.md5($realm).'"');
    $_SESSION['logged'] = False;
    die('Access denied.');
  }
  $_SESSION['logged'] = True;  
}

function IsAuthenticated(){
  global $realm;
  global $users;


  if  (empty($_SERVER['PHP_AUTH_DIGEST']))
      return False;

  // check PHP_AUTH_DIGEST
  if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
     !isset($users[$data['username']]))
     return False;// invalid username


  $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
  $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);

  // Give session id instead of data['nonce']
  $valid_response =   md5($A1.':'.$_SESSION['session_id'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

  if ($data['response'] != $valid_response)
    return False;

  return True;
}
7
Pie86

Sobald ein Browser den Benutzer nach Anmeldeinformationen gefragt und diese an eine bestimmte Website übermittelt hat, wird er dies normalerweise ohne weitere Aufforderung tun. Im Gegensatz zu den verschiedenen Möglichkeiten zum Löschen von Cookies auf der Clientseite ist mir keine ähnliche Möglichkeit bekannt, wie der Browser gebeten wird, die angegebenen Authentifizierungsdaten zu vergessen.

4
Greg Hewgill

Dies ist möglicherweise nicht die Lösung, nach der gesucht wurde, aber ich habe sie so gelöst. Ich habe 2 Skripts für den Logout-Prozess.

logout.php

<?php
header("Location: http://[email protected]/log.php");
?>

log.php

<?php
header("location: https://google.com");
?>

Auf diese Weise bekomme ich keine Warnung und meine Sitzung ist beendet

2
Kevin

Trac verwendet standardmäßig auch die HTTP-Authentifizierung. Logout funktioniert nicht und kann nicht behoben werden:

  • Dies ist ein Problem mit dem HTTP-Authentifizierungsschema selbst. Wir können in Trac nichts tun, um es richtig zu beheben.
  • Derzeit gibt es keine Problemumgehung (JavaScript oder andere), die mit allen gängigen Browsern funktioniert.

From:http://trac.edgewall.org/ticket/791#comment:103

Anscheinend gibt es keine funktionierende Antwort auf die Frage, dieses Problem wurde vor sieben Jahren gemeldet und ist absolut sinnvoll: HTTP ist zustandslos. Entweder wird eine Anforderung mit Authentifizierungsdaten abgerufen oder nicht. Dies ist jedoch eine Frage des Clients, der die Anfrage sendet, nicht des Servers, der sie empfängt. Der Server kann nur sagen, ob ein Anforderungs-URI eine Autorisierung benötigt oder nicht.

2
hakre

Ich musste die .htaccess-Autorisierung zurücksetzen, also habe ich Folgendes verwendet:

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    echo 'Text to send if user hits Cancel button';
    exit;
}
?>

Fand es hier: http://php.net/manual/de/features.http-auth.php

Stelle dir das vor.

Eine Reihe von Lösungen befindet sich auf dieser Seite und es wird sogar am unteren Rand darauf hingewiesen: Lynx löscht die Auth nicht wie andere Browser;)

Ich habe es auf meinen installierten Browsern getestet, und sobald es geschlossen ist, scheint jeder Browser den Wiedereintritt durchgängig zu erfordern.

2
Dooley

AFAIK, es gibt keine saubere Möglichkeit, eine "Logout" -Funktion zu implementieren, wenn die Authentifizierung mit htaccess (d. H. HTTP) verwendet wird.

Dies liegt daran, dass bei einer solchen Authentifizierung der HTTP-Fehlercode "401" verwendet wird, um dem Browser mitzuteilen, dass Anmeldeinformationen erforderlich sind. Zu diesem Zeitpunkt fordert der Browser den Benutzer zur Eingabe der Details auf. Von da an, bis der Browser geschlossen wird, werden die Anmeldeinformationen immer ohne weitere Aufforderung gesendet.

1
Alnitak

Die beste Lösung, die ich bisher gefunden habe, ist (es ist eine Art Pseudo-Code, der $isLoggedIn ist eine Pseudovariable für http auth):

Zum Zeitpunkt der "Abmeldung" speichern Sie einfach einige Informationen in der Sitzung, die besagen, dass der Benutzer tatsächlich abgemeldet ist.

function logout()
{
  //$isLoggedIn = false; //This does not work (point of this question)
  $_SESSION['logout'] = true;
}

An der Stelle, an der ich auf Authentifizierung prüfe, erweitere ich die Bedingung:

function isLoggedIn()
{
  return $isLoggedIn && !$_SESSION['logout'];
}

Die Sitzung ist in gewisser Weise mit dem Status der http-Authentifizierung verknüpft, sodass der Benutzer abgemeldet bleibt, solange der Browser geöffnet bleibt und die http-Authentifizierung im Browser bestehen bleibt.

1
Josef Sábl

Vielleicht fehlt mir der Punkt.

Die zuverlässigste Methode zum Beenden der HTTP-Authentifizierung besteht darin, den Browser und alle Browserfenster zu schließen. Sie können ein Browserfenster mit Javascript schließen, aber ich glaube nicht, dass Sie alle Browserfenster schließen können.

1
Toby Allen

Hier gibt es viele großartige - komplexe - Antworten. In meinem speziellen Fall habe ich eine saubere und einfache Lösung für das Logout gefunden. Ich habe noch keinen Test in Edge . Auf meiner Seite, auf der ich mich angemeldet habe, habe ich einen ähnlichen Abmelde-Link gesetzt:

<a href="https://MyDomainHere.net/logout.html">logout</a>

Und im Kopf dieser logout.html-Seite (die auch durch den .htaccess geschützt ist) habe ich eine Seitenaktualisierung ähnlich der folgenden:

<meta http-equiv="Refresh" content="0; url=https://logout:[email protected]/" />

Wo würden Sie die Worte "Logout" belassen, um den Benutzernamen und das Passwort für die Site zu löschen.

Ich gebe zu, dass, wenn mehrere Seiten von Anfang an direkt angemeldet sein müssen, für jede dieser Eintrittsstellen eine eigene entsprechende logout.html-Seite erforderlich wäre. Ansonsten könnten Sie die Abmeldung zentralisieren, indem Sie vor der eigentlichen Anmeldeaufforderung einen zusätzlichen Gatekeeper-Schritt in den Prozess einführen, der die Eingabe einer Phrase erfordert, um ein Anmeldungsziel zu erreichen.

0
johnwayne

Während die anderen zu Recht sagen, dass es unmöglich ist, sich von der grundlegenden http-Authentifizierung abzumelden, gibt es Möglichkeiten, eine Authentifizierung zu implementieren, die sich ähnlich verhält . Ein naheliegender Ansatz ist die Verwendung von auth_memcookie . Wenn Sie die Standard-HTTP-Authentifizierung wirklich implementieren möchten (dh die Browser-Dialogfelder zum Anmelden anstelle eines HTTP-Formulars verwenden), stellen Sie die Authentifizierung einfach auf ein separates .htaccess-geschütztes Verzeichnis ein, das ein PHP-Skript enthält, das umleitet Zurück, wohin der Benutzer nach dem Erstellen der Memcache-Sitzung gekommen ist.

0
symcbean

Die einzige effektive Methode, die ich gefunden habe, um die PHP_AUTH_DIGEST- oder PHP_AUTH_USER- und PHP_AUTH_PW-Berechtigungsnachweise zu löschen, ist den Header HTTP/1.1 401 Unauthorized aufzurufen.

function clear_admin_access(){
    header('HTTP/1.1 401 Unauthorized');
    die('Admin access turned off');
}
0
CIRCLE