php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
WWW-Authenticate: Basic => wie ausloggen


 
Troublegum
26-05-2002, 02:50 
 
Hallo,

ich bräuchte mal Rat.
Da ich mir die Mühe für eine Loginsystem sparen will, identifiziere ich den Benutzer wie folgt:


$loginname = $_SERVER['PHP_AUTH_USER'];
$password = encrypt_password($_SERVER['PHP_AUTH_PW']);
// gekürzt (Passwort-Vergleich)
if(!$user_info['user_id'])
{
unset($user_info);
unset($loginname);
unset($password);
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Restricted Area"');
echo "Access Denied.";
exit;
}


Das klappt auch wunderbar.
Wie kann ich mich als Benutzer ausloggen, ohne den Browser zu schließen ? Bei Confixx geht es auch irgendwie.

Ach so: Und diese Methode; funktioniert die nur bei Apache und ist sie sicher ?

MfG Troublegum

 
hand
26-05-2002, 11:31 
 
Mich wundert es, dass Deine Frage so selten gestellt wird. Wenn Sie gestellt wird ist meist die Antwort, ja man hätte gelesen daß dies ganz easy funktioniert. Es werden Links gepostet, die angeblich das Problem und die Lösung beschreiben. Oder Antworten wie "ja irgendwie ..." "Man hätte gehört man bräuchte nur den Returncode xyz an den Brwoser senden".
Das alles ist zu 99% Quatsch. Und wenn hier einer durch meine Ausdrucksweise provoziert den Gegentbeweis antritt, dann solls uns allen Recht sein.

Ich habe mich intensiv mit diesem Thema beschäftigt und mich festgebissen. Auslöser dafür war dieselbe Frage in einem anderen Forum.

Nach wirklich tagelangen Recherechen, Lesen aller Basics: Es geht nicht! Diese Möglichkeit ist einfach nicht vorgesehen, was mich wundert. Das was herauskam, war eine Umgehung des Problems durch "Ummelden".

Funktionsprinzip: Der Browser überträgt in seinem Header bei jeder Interaktion UID und PWD an den Server. Beim ersten Kontakt mit einer über htaccess geschützten Seite wird, nachdem UID und PWD noch nicht belegt sind das Login-Fenster gepromptet. Die Login-Daten an den Server gesendet, dort überprüft und wenn die Eingabe Korrekt war dem Browser bestätigt, der dann diese Login-Informationenen im Speicher behält. Erfolgt die Autentifizierung über PHP ist das Prinzip dasselbe.

ftp://ftp.isi.edu/in-notes/rfc2617.txt

So und nun wie ich das Problem umgangen habe. Meine Umgehungsmethode lautet "Ummeldung", die aber zur Zeit leider nur im Zusammenhang mit dem IExplorer funktioniert, nicht mit Netscape, warum das so ist etwas später.

Meine Applikation, die das nutzt liegt in einem über htaccess geschützen Verzeichnis. Der Login erfolgt dadurch über das gepromptete Browser-Loginfenster. Ich nutze die Möglichkeit der Autentifizierung via PHP in diesem Fall nicht, was aber ansich keine Rolle spielen dürfte.

Für das Ereignis "Logout" habe ich einen User angelegt mit UID "logout" und PWD "logout". Dieser User hat keine Rechte mit der Applikation zu arbeiten. Diese UID PWD Kombination kann ruhig transparent und theorethisch öffentlich zugänglich sein, da der Benutzer "logout" ohnehin keine Rechte bestitzt.

Wird auf den Button oder Link "Logout" geklickt so übertrage ich die neue Benutzerkennung "logout" an den Server:

1. Schritt mit: "HTTP://$username:$password@$domain"
unmittelbar danach
2. Schritt mit: "HTTP://$domain"

Dafür nutze ich
meta http-equiv="refresh content="1; URL=..."

Der zweite Schritt dient dem Umstand, daß UID:PWD nach dem Ummeldevorgang im Adressfeld weiter angezeigt wird.

Mit diesem Feature ist es möglich dem Benutzer ein direktes Ummelden anzubieten.

Warum das ganze nur unter IExplorer astrein funktioniert? Netscape beeindruckt die Mitgabe von Benutzerkennung und Passwort nicht (HTTP://$username:$password@$domain), wenn eine Autentifizierung zuvor bereits erfolgt ist.

Da gibt es sicher auch noch eine Lösung dafür, aber das war mir dann doch nicht so wichtig, wenns notwendig ist, werde ich sicher was finden.

Vielleicht findest Du was?

Nächster Punkt Sicherheit: UID und PWD werden natürlich über die Leitung übertragen. Ist die Verbindung verschlüsselt kann der Datenstrom schwer entschlüsselt werden. Wenn unverschlüsselt, laufen die Daten wie ein Ticker im Klartext bei einem Sniffer vorbei. Das ist aber ein generelles Problem.

Die Autentifizierungsmethode-Methode über PHP funktioniert nur bei Apache.

So damit nicht alles so theoretisch ist:

<!-- BEGIN TEMPLATE: login.inc -->
<?

$LIN_SN = getenv("SCRIPT_NAME");

if (isset($username) && isset($password)) {
//print "isset1: $username $password $login";
$FORWARD_STEP1 = "\"refresh\" content=\"1; URL=$LIN_CONN://$username:$password@$LIN_IP".$LIN_SN."?lstep2=\">";
print "
<html>
<head>
<meta http-equiv=$FORWARD_STEP1
</head>
<body>
<table border='0' cellspacing='0' cellpadding='0' width='150'>
<tr><td class=basic>
<table width='150' border='0' cellspacing='1' cellpadding='3'>
<tr><th class=top>&nbsp;<font color='#000000'><b>User's Login</b></font></th></tr>
<tr><td>".print date("d.m.y H:i:s", time())."<br>"."Login/Logout Step 1<br>please wait ...</td></tr>
</table>
</td></tr>
</table>
</body>
</html>
\n";
exit;
}

if (isset($lstep2)) {
//print "isset2: $lstep2";
$FORWARD_STEP2 = "\"refresh\" content=\"1; URL=$LIN_CONN://$LIN_IP".$LIN_SN."\">";
print "
<html>
<head>
<meta http-equiv=$FORWARD_STEP2
</head>
<body>
<table border='0' cellspacing='0' cellpadding='0' width='150'>
<tr><td class=basic>
<table width='150' border='0' cellspacing='1' cellpadding='3'>
<tr><th class=top>&nbsp;<font color='#000000'><b>User's Login</b></font></th></tr>
<tr><td>".print date("d.m.y H:i:s", time())."<br>"."Login/Logout Step 2<br>please wait ......</td></tr>
</table>
</td></tr>
</table>
</body>
</html>
\n";
exit;
}
?>
<table border="0" cellspacing="0" cellpadding="0" width="150">
<tr>
<td class=basic>
<table width="150" border="0" cellspacing="1" cellpadding="3">
<tr><th class=top>&nbsp;<font color="#000000"><b>User's Login</b></font></th></tr>
<tr><td><font size="1">
<?
print date("d.m.y H:i:s", time())."<br>\n";
$D_USER = $PHP_AUTH_USER;
if ($PHP_AUTH_USER == "" || $PHP_AUTH_USER == "logout") {
$D_USER = "<strong>Logged Out</strong>";
}
print "User: $D_USER [$P_USERREST[$PHP_AUTH_USER]]<br>\n";
print "IP: ".$REMOTE_ADDR."\n";
if (eregi("MSIE",getenv("HTTP_USER_AGENT"))) {
?>
<form action="<?print basename(getenv("SCRIPT_NAME"));?>" method="post">
<input type="hidden" name="action" value="login">
<input type="hidden" name="url" value="/index.php">
<table border="0" cellpadding="0" cellspacing="0" width=100%>
<tr>
<td align=center><font size="1"><b>Username&nbsp;</b></font></TD><TD align=center><font size="1"><b>Password&nbsp;</b></font></TD>
</tr><tr>
<TD align=center><INPUT TYPE="TEXT" NAME="username" SIZE=7></TD><TD align=center><INPUT TYPE="PASSWORD" NAME="password" SIZE=7></TD>
</TR><TR>

<?
if ($PHP_AUTH_USER == "" || $PHP_AUTH_USER == "logout") {
?>
<td colspan=2 valign=midel align=center><center>
<input type='image' src='button.php?WIDTH=50&TEXT=+Login!' border='0' name='login' value='login' alt='Login!'>
</center>
<?
} else {
?>
<TD valign="middle" align=center>
<input type='image' src='button.php?WIDTH=50&TEXT=ReLogin' border='0' name='login' value='login' alt='Login!'></TD>
<TD valign="middle" align=center><a href=<?print basename(getenv("SCRIPT_NAME"))."?username=logout&password=logout";?>>
<img src='button.php?WIDTH=50&TEXT=+Logout' border='0' name='login' value='login' alt='Login!'></a>
<?
}
?>
</td></tr>
</table>
</form>
<?
}
?>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- END TEMPLATE: login.inc -->

 
hand
26-05-2002, 11:41 
 
Noch was:

Gem. php.net sollte es wie folgt funktionieren:

"Sowohl Netscape als auch der Internet Explorer löschen den lokalen Authentifizierungscache des Browserfensters, wenn der Server eine 401-Meldung zurückgibt. Dies kann benutzt werden, um einen Benutzer "auszuloggen" und eine erneute Eingabe des Benutzernamens/Passworts zu erzwingen. Manchmal wird dieses Verhalten für das automatische Ausloggen nach Ablauf einer bestimmten Zeitspanne oder für einen Logout-Button genutzt."

Das die Theorie, hier die Praxis ...

<?php
Header( "HTTP/1.0 401 Unauthorized");
echo "Logout erfolgreich";
exit();
?>

So hat es angefangen, mit o.a. Umgehung hats geendet.

 
Troublegum
26-05-2002, 12:12 
 
Hallo hand :) ,

danke für Deine Antwort, das hat mir sehr weitergeholfen.
Fasse ich nochmal zusammen:

Entweder per URL neue Userdaten (auch falsche) weitergeben und dann wieder zurück ...
oder eine 401 Meldung senden.

Ich habe beide Methode ausprobiert, die 2. sagt mir ehrlich gesagt mehr zu. Auch wenn es bei mir nicht auf Anhieb funktionierte, ich musste noch folgendes senden:
header('WWW-Authenticate: Basic realm="Webcvs Restricted Area"');
Also läuft es praktisch bei beiden Methoden darauf hinaus, den Benutzer ein neues Passwort eingeben zu lassen bzw. ihm ein neues zuzuweisen.

Danke dir nochmal.

MfG Troublegum

 
hand
26-05-2002, 12:50 
 
Also läuft es praktisch bei beiden Methoden darauf hinaus ...
Bei 2. Methode schon. Aufgrund des 401er wird eine Eingabe erzwungen. Brichst Du die Eingabe ab, bleibst Du angemeldet.
Ich kann mich nicht mehr erinnern, liegt schon ein halbes Jahr zurück, woran es bei Methode 2 gehakt hat. Ich habe es zumindest nicht geschafft. Weshalb ich dann genötigt war die Umgehungsmethode 1, die ja wirklich nicht vom Feinsten ist, zu coden. Wenn Methode 2 so funktionieren würde wie theoretisch beschrieben, hätte ich nie ein Problem gehabt. Und wenn ein 401er einen Login-Prompt verursacht ist das sicher am Thema vorbei, das kann man ja keinem Benutzer verklickern. Ich hoffe Du schaffst es mit Methode 2, wenn ja, gib bitte Bescheid.

Also läuft es praktisch bei beiden Methoden darauf hinaus ...
Bei 1. Methode nicht. Da übergibst Du ja UID "logout" mit PWD "logout". Du meldest faktisch im Hintergrund auf den User "logout" um. Haken dabei, wie schon erwähnt, funzt wie oben beschrieben nur mit IExplorer. Netscape ist aber sicher auch zu knacken. Methode 1 schaut komplizierter aus, als sie ist.

Wenn Du über Methode 1 falsche Autentifizierungsdaten sendest, wird natürlich auch der Login gepromptet. Das alles gilt natürlich für htaccess geschützte Verzeichnisse. Autentifizierung via PHP hab ich mir in diesem Zusammenhang nicht extra angeschaut.

 
TheUser
26-05-2002, 13:58 
 
wieso kann man die PHP_AUTH Variablen nicht mit unset löschen?

 
hand
26-05-2002, 14:38 
 
Weil sich der Inhalt im Authentifizierungscache des Browsers befindet und beim nächsten Request wieder an den Server gesandt wird und so wieder gesetzt ist.

Das Einzige was hilft ist clientside den Authentifizierungscache des Browsers zu löschen oder wie in Methode 1 umzusetzen.

 
Troublegum
26-05-2002, 15:09 
 
Hallo hand,

Ich erahne nun, wie Confixx es macht (Datenbankstruktur gesehen :rolleyes: ).

Die Benutzerdaten werden in der Datenbank gesichert (genauso wie bei mir -> nicht in .htpasswd) und beim Login wird der Wert eines Feldes namens "login" auf 1 gesetzt.
Nur, wenn die Zugangsdaten stimmen und login 1 ergibt, wird man vom System zugelassen.

Bei einem Klick auf Logout wird einfach login auf 0 zurückgesetzt.
Ob noch eine 401-Meldung gesendet wird, kann ich nicht sagen.
Das Ergebnis ist aber das selbe. Wenn login nicht 1 ergibt, ist man auf keinen Fall eingeloggt, man muss sich neu einloggen.

Ich denke doch, dass das eine akzeptable Lösung ist, oder was meinst du ?

MfG Troublegum

 
hand
26-05-2002, 17:30 
 
Ja sicher das ist praktikabel. Für diese Lösung muß das Login-Kennzeichen entweder via Sessionvariable oder über einen Datenbank- oder Fileeintrag mitgeführt werden.

Der Nachteil der 'WWW-Authenticate' Methode ist sicher, daß UserID und PWD bei jedem nachfolgenden Request übertragen wird, bis das Browserfenster geschlossen wird.

Der Vorteil ist nur im Zusammenhang mit .htaccess zu sehen. Ohne .htaccess sehe ich eigentlich keinen Sinn. Wenn ich .htaccess verwende kann ein Fremdling :D nicht einmal ein simples PIC aus dem geschützen Verzeichnis laden, ohne sich zu authentifizieren. Wenn das gewollt ist bietet sich 'WWW-Authenticate' an, wenn nicht würde ich darauf verzichten. Für diesen Fall Dann wäre es einfacher die Anmeldung ganz simpel abzuhandeln, das Login-Kennzeichen zu setzen, alle weiteren Infos über Sessionvariable weiterzureichen.


Alle Zeitangaben in WEZ +2. Es ist jetzt 03:46 Uhr.