|
|
Capitolo 18. Autenticazione HTTP usando PHP
I meccanismi di Autenticazione HTTP sono disponibili in PHP solo quando questo
viene usato come un modulo di Apache ed esso non � quindi disponibile nella versione CGI.
In uno script PHP modulo di Apache, � possibile usare la
funzione header() per inviare un messaggio di "Authentication Required"
al browser dell'utente, provocando quindi l'apertura di una finestra contenente una richiesta di
Nome utente/Password. Una volta che l'utente ha compilato i campi nome utente e password,
l'URL contenente lo script PHP verr� richiamato nuovamente usando le variabili,
$PHP_AUTH_USER, $PHP_AUTH_PW e $PHP_AUTH_TYPE impostate con, rispettivamente:
nome, password e tipo di autenticazione. Solamente il tipo di autenticazione "Basic"
� al momento supportato. Fare riferimento alla funzione header()
per ulteriori informazioni.
Un frammento di script di esempio che richiede l'autenticazione da parte del browser
su una pagina, potrebbe essere il seguente:
Esempio 18-1. Esempio di Autenticazione HTTP <?php
if (!isset($PHP_AUTH_USER)) {
header("WWW-Authenticate: Basic realm=\"Il mio realm\"");
header("HTTP/1.0 401 Unauthorized");
echo "Messaggio da inviare se si preme il tasto Cancel\n";
exit;
} else {
echo "<p>Ciao $PHP_AUTH_USER.</p>";
echo "<p>Hai inserito $PHP_AUTH_PW come tua password.</p>";
}
?> |
|
Note:
Fare molta attenzione quando si scrive codice per le intestazioni HTTP. Per ottenere la massima
compatibilit� con tutti i client, la paorla-chiave "Basic" deve essere scritta con una
"B" maiuscola, la stringa realm deve essere racchiusa in virgolette doppie (non singole),
ed esattamente uno spazio deve precedere il codice "401" nella linea di intestazione "HTTP/1.0 401".
Invece di stampare semplicemente $PHP_AUTH_USER e
$PHP_AUTH_PW, probabilmente si vorr� controllare la validit� dello username e
della password. Probabilemnte inviando una chiamata al database,
o cercando un utente in un file dbm.
Si faccia attenzione ad alcune versioni di Internet Explorer. Sembra
che siano molto schizzinosi riguardo all'ordine delle intestazioni. Inviare l'intestazione
WWW-Authenticate prima dell'intestazione
HTTP/1.0 401 sembra sistemare le cose per
il momento.
Al fine di prevenire che qualcuno scriva uno script che rivela
la password di una pagina che era stata autenticata tramite un tradizionale
meccanismo esterno, le variabili PHP_AUTH non verranno
impostate se � abilitata l'autenticazione esterna per quella determinata
pagina. In questo caso, la variabile $REMOTE_USER pu� essere usata per
identificare un utente autenticato esternamente. Nota sulla Configurazione:
PHP usa la presenza di una direttiva AuthType
per determinare se viene utilizzata l'autenticazione esterna.
Evitare questa direttiva nel contesto dove si intende
usare l'autenticazione con PHP (altrimenti ogni tentativo di autenticazione
fallir�).
Si fa notare, per�, che quanto scritto sopra non impedisce a qualcuno che
controlla un URL non autenticato di sottrarre password da
URL autenticati presenti sullo stesso server.
Sia Netscape Navigator che Internet Explorer cancellano la cache locale
della finestra del browser, per quanto riguarda il realm, al ricevimento
di una risposta 401 da parte del server. Questo � effettivamente un meccanismo di "log out" per l'utente,
che lo forza a reinserire lo username e la password. Alcune persone
usano questo per fare il "time out" dei login, o per rendere disponibili bottoni di "log-out".
Esempio 18-2. Esempio di Autenticazione HTTP che impone l'inserimento di nuovo username/password <?php
function authenticate() {
header( "WWW-Authenticate: Basic realm=\"Prova del Sistema di Autenticazione\"");
header( "HTTP/1.0 401 Unauthorized");
echo "Per poter accedere a questa risorsa occorre inserire una coppia login e password valide\n";
exit;
}
if (!isset($PHP_AUTH_USER) || ($SeenBefore == 1 && !strcmp($OldAuth, $PHP_AUTH_USER))) {
authenticate();
}
else {
echo "<p>Benvenuto: $PHP_AUTH_USER<br>";
echo "Vecchio: $OldAuth";
echo "<form action='$PHP_SELF' method='POST'>\n";
echo "<input type='HIDDEN' name='SeenBefore' value='1'>\n";
echo "<input type='HIDDEN' name='OldAuth' value='$PHP_AUTH_USER'>\n";
echo "<input type='submit' value='Re Authenticate'>\n";
echo "</form></p>\n";
}
?> |
|
Questo comportamento non � richiesto dallo standard di autenticazione HTTP
Basic, quindi non si dovrebbe mai fare affidamento su di esso. Test effettuati con Lynx
mostrano che Lynx non cancella le credenziali di autenticazione
al ricevimento del codice di risposta 401 da parte del server, quindi, premendo indietro e avanti
nuovamente, dar� nuovamente accesso alla risorsa, ammesso che le rispettive richieste di credenziali
non siano cambiate. L'utente pu� per� premere il
tasto '_' al fine di cancellare le sue informazioni di autenticazione.
Si noti anche che questo non funziona con il server IIS di Microsoft e
con la versione CGI di PHP a causa di una limitazione di IIS.
Nota:
Se � abilitato safe mode viene
aggiunto lo uid dello script al realm
dell'header WWW-Authenticate.
User Contributed Notes Autenticazione HTTP usando PHP |
|
[email protected]
21-Jul-1999 10:02 |
|
A few notes on authentication in which it's possible I overlooked some
things. Considering a prior post about using the same salt for all users
so you can match passwords; I think it would be better to not do so, as
you can figure out the salt from the password and match. (Example, salt
in DES if I'm not mistaken is the first 2 characters)
Something I've
been trying to figure out is secure apache module PHP on a multi-user
server.
Delima (with postgres)- any user can write a PHP page to
read another users databases. Set your database to connect using username
and password, and any user can read your username and password from
wherever you place them. (use PHP function to read it and as it has to be
readable by your web process for you to read it, they can)
The
closest I've come to a solution for this is to run php as a CGI module
with suexec or cgiwrap.
Hopefuly someone else has a better
solution; otherwise, something to think about before you think of your
databases as being secure with php interfacing to them.
|
|
[email protected]
18-Dec-1999 01:42 |
|
Someone gave me a simple solution to the 'logout' problem: add some sort of
timestamp to the basic realm you send in the WWW_Authenticate header. Mine
now is: $realm="RealmName (
".strftime("%c",time())." )";. (btw: the problem
was: 1) IE4 asks for the page one more time after a 401, defeating sending
a 401 once to force a user to log on again. and 2) IE4 remembers the
password, and puts it default in the logon window. Changing the realm
solves these problems, not the 'logon failed' message of NS though).
|
|
[email protected]
09-Feb-2000 06:59 |
|
I had the same problem as above (that is, with apache I can't get the auth
info). The solution I found goes like this:
$headers =
getallheaders();
$auth=$headers[authorization];
if ($auth=='') {
$auth=$headers[Authorization];
}
if($auth=='')
{
Header("WWW-Authenticate: Basic
realm=\"$PROG_NAME\"");
Header("HTTP/1.0 401
Unauthorized");
}
list($user, $pass) =
explode(":", base64_decode(substr($auth, 6)));
|
|
[email protected]
19-May-2000 09:31 |
|
Here is a code for the public sites enabling both logout bottom and timeout
using php+mysql. Working for both browsers.
The part
"required" for each user protected
page:
<?
function auth () {
Header("WWW-Authenticate: Basic realm=\"ArmFN public
site\"");
Header("HTTP/1.0 401
Unauthorized");
echo "You have to authentificate
yourself first \n";
exit;
}
mysql_connect("localhost","train","")
or die("Unable to connect to SQL server");
mysql_select_db(
"train") or die( "Unable to select database");
if(!isset($PHP_AUTH_USER)) {
$timeout =
mktime(date(G),date(i)+10,0,date("m"),date("d"),date("Y"));
mysql_query("update
users set login='$timeout' where id='$user' and pasw='$pass'") or
die("k");
auth();
} else {
$pass = $PHP_AUTH_PW;
$user = $PHP_AUTH_USER;
$nowtime =
mktime(date(G),date(i),0,date("m"),date("d"),date("Y"));
$quer2
= mysql_query("select * from users where id='$user' and pasw='$pass'
and login > '$nowtime'") or die("kuk2");
if
(mysql_num_rows($quer2) == "0") {
$timeout =
mktime(date(G),date(i)+10,0,date("m"),date("d"),date("Y"));
mysql_query("update
users set login='$timeout' where id='$user' and pasw='$pass'") or
die("k");
auth();
}
}
?>
You
can have a "logout" bottom with hidden $go="logout"
form element and then have somewhere this part:
if ($do ==
"logout")
{
mysql_connect("localhost","train","")
or die("Unable to connect to SQL server");
mysql_select_db(
"train") or die( "Unable to select database");
mysql_query("update users set login=0 where id='$PHP_AUTH_USER'
and pasw='$PHP_AUTH_PW'") or die("k");
}
|
|
[email protected]
30-Aug-2000 10:04 |
|
Good day.I've solved a problem where IE4 asks for the age one more time
after a 401, defeating sending a 401 once to force a user to log on
again.
function authenticate() {
setcookie("noauth","");
Header(
"WWW-authenticate: Basic realm=\"test\"");
Header( "HTTP/1.0 401 Unauthorized");
echo "You must
enter user name";
exit ;
}
if (
!isset($PHP_AUTH_USER) || ($logoff==1) &&
$noauth=="yes" ) {
authenticate();
}
And logoff link -
<a
href="samehtml.phtml?logoff=1">Logoff</a></td>
Dmitry
Alyekhin
|
|
[email protected]
16-Oct-2000 10:01 |
|
The new Mozilla browser doesn't seem to like the switched authentication
lines.
This doesn't work (I have build
2000101308):
Header( "WWW-authenticate: Basic
realm=\"test\"");
Header( "HTTP/1.0 401
Unauthorized");
The first time you authenticate all seems
ok, but the second time it always returns unauthorized.
This
works as it should:
Header( "HTTP/1.0 401
Unauthorized");
Header( "WWW-authenticate: Basic
realm=\"test\"");
|
|
[email protected]
10-Mar-2001 09:19 |
|
I suggest to read RFC2617 (HTTP Authentication: Basic and Digest Access
Authentication) and related RFCs.
|
|
k u d o s@t e l u s p l a n e t . n e t
05-Apr-2001 06:19 |
|
Thanks to [email protected] for the rfc note needed to solve this
one. This looks like it flushed out the authentication headers on both
Netscape and IE:
Header("WWW-Authenticate: Basic
realm=\"Whatever Realm\", stale=FALSE");
|
|
|
[email protected]
12-Jun-2001 10:53 |
|
This is a good resource for setting up htaccess schemes:
The
windows version of apache comes with htpasswd.exe in the apache\bin
directory.
The only thing that present problems is you have to
change your .htaccess file to point to the created password file (ie
C:\directory\passwords.file)....so if you transfer the file back to a *nix
server it wont find your file.
One (temporary) workaround is
changing your local httpd.conf file to point to a different access
file:
AccessFileName htaccess.
You just have to make
sure to syncronize your access files.
Im not sure if you can
point your htaccess to two password files??
AuthName "restricted
stuff"
AuthType Basic
AuthUserFile
/usr/local/etc/httpd/users
AuthUserFile
C:\directory\password.file
require valid-user
|
|
[email protected]
12-Jul-2001 08:51 |
|
If register_globals is turned off PHP_AUTH_USER and PHP_AUTH_PW variables
will not be set, instead they are stored in $HTTP_SERVER_VARS array as
$HTTP_SERVER_VARS['PHP_AUTH_USER'] and HTTP_SERVER_VARS['PHP_AUTH_PW'].
|
|
[email protected]
28-Jan-2002 06:25 |
|
Restrict access by username, password AND ip
address:
<? function authenticate()
{ header("WWW-Authenticate: Basic
realm=\":-!\""); header("HTTP/1.0 401
Unauthorized"); print("You must enter a valid login username
and password to access this
resource.\n"); exit; } if(!isset($PHP_AUTH_USER)){
authenticate(); } else
{ $c=mysql_pconnect("server.name","user","password"); mysql_select_db("dbname",$c); $q=sprintf("SELECT
username,password FROM authenticateTable WHERE username='%s' AND
password=PASSWORD('%s') AND
ipaddress='%s'", $PHP_AUTH_USER,$PHP_AUTH_PW,$REMOTE_ADDR); $q=mysql_query($q); if(mysql_num_rows($q)==0){
authenticate(); } } ?>
|
|
[email protected]
29-Jan-2002 10:00 |
|
To get it to work with IIS try using this code before setting your
"$auth = 0" and the "if (isset($PHP_AUTH_USER) &&
isset($PHP_AUTH_PW))"
//////////////////////////////////////////
if
($PHP_AUTH_USER == "" && PHP_AUTH_PW == ""
&& ereg("^Basic ", $HTTP_AUTHORIZATION)) {
list($PHP_AUTH_USER, $PHP_AUTH_PW) = explode(":",
base64_decode(substr($HTTP_AUTHORIZATION, 6)));
}
//////////////////////////////////////////
It worked
for me on IIS 5 and PHP 4 in ISAPI
|
|
[email protected]
22-Feb-2002 07:09 |
|
I tried the method posted by [email protected] for a logout feature,
which seems to be a problem for users of http authentication. Tigran's
method is perfect, except that after you log out, you can STILL access the
pages by clicking on "cancel" when prompted again by the Java
window. This will trigger the 401 error. But it will also create an
entry in the history folder.
You will notice the
"forward" button on your browser becomes clickable. You only
have to click on the that "forward" button to be able to access
the protected pages.
I have found a solution for this problem by
using a little Javascript to refresh to another page.
Please go to
my website for details:
|
|
[email protected]
01-Mar-2002 12:49 |
|
I use apache's built in support for .htaccess, and the following function
to grab user details as required.
Function GetHttpAuth() {
$headers = getallheaders(); $auth=explode("
",$headers[Authorization]); if ($auth=='') { $auth=explode("
" ,$headers[authorization]); }
$authdec=base64_decode($auth[1]);
$autharray=explode(":",$authdec);
$authname=$autharray[0]; $authpass=$autharray[1];
return($autharray); }
|
|
[email protected]
24-May-2002 03:22 |
|
The definitive HTTP authorization code:
function
login_error() { echo "error - login process
failed." }
if (!isset($PHP_AUTH_USER)) {
header("WWW-Authenticate: Basic realm=\"Mosaic Authorization
process\""); header("HTTP/1.0 401
Unauthorized");
//Result if user hits cancel button
login_error(); } else {
//check the login and
password if('=>test on login and password<=') { //User
is logged ... ... } else { //This re-asks three
times the login and password. header( "WWW-Authenticate: Basic
realm=\"Test Authentication System\"");
header("HTTP/1.0 401 Unauthorized");
//Result if user
does not give good login and pass login_error(); } }
|
|
[email protected]
02-Jun-2002 06:29 |
|
Using the same salt for all things is a bad idea.
Use the first two
letters of the username - this also makes moving to other .htaccess based
systems easier :)
|
|
05-Jun-2002 09:08 |
|
A more elegant way to force a new name/password, cf. example 17-2 (if you
don't mind passing the old user in the query string):
<? if
(isset($PHP_AUTH_USER)) { if
(!isset($prev_user)) { header("Location: ); exit; } else { if
($PHP_AUTH_USER == $prev_user) { header('WWW-Authenticate:
Basic realm="Secure"'); header('HTTP/1.0 401
Unauthorized'); exit; } } } else { header('WWW-Authenticate:
Basic realm="Secure"'); header('HTTP/1.0 401
Unauthorized'); exit; } ?>
The final set of headers is
necessary because some browsers seem to unset $PHP_AUTH_USER when the
location header is sent.
|
|
20-Jun-2002 04:30 |
|
Seems that REMOTE_USER is only set in .htaccess Authentification not in PHP
header Authentifications
|
|
[email protected]
29-Jul-2002 03:20 |
|
To "logout" of HTTP Auth all you have to do it unset
PHP_AUTH_USER & PHP_AUTH_PW.
I came across this function and it
works really well.
Below is what i use.(minus a few MySQL
vars)
if($lo == 1) { $phpuser =
unset($GLOBALS['_SERVER']['PHP_AUTH_USER']); $phppass =
unset($GLOBALS['_SERVER']['PHP_AUTH_PW']); if(($phpuser ==
"") && ($phppass == "")) { echo
"Now Logged out.<br />"; exit;
} }
I hope this helps some of you. (if anyone knows who wrote
this, please post name below)
|
|
07-Aug-2002 12:44 |
|
A quick comment to Jason's note:
As of PHP 4 unset() doesn't return
a value, so $var = unset($anothervar); will result in a parse error.
You could test the result with isset($anothervar) instead.
|
|
[email protected]
07-Aug-2002 06:24 |
|
I have written a class for HTTP Authentication in PHP. Anyone looking for a
shortcut can get it from:
Feel
free to make suggestions and contributions to the class. It needs some
improvement.
|
|
[email protected]
09-Aug-2002 04:09 |
|
Hello all,
I've just found a great article about authentification in
php with and without the apache environment, it's as flexible as can be
and it works really great and secure.
See for yourself at
|
|
|
| |