Autenticazione HTTP usando PHP
È 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 predefinite,
PHP_AUTH_USER, PHP_AUTH_PW e
AUTH_TYPE impostate con nome, password e
tipo di autenticazione. Queste variabili predefinite possono essere trovate
negli array $_SERVER e
$HTTP_SERVER_VARS. Saranno supportati entrambi i
metodi di autenticazione, "Basic" e "Digest" (a partire dal PHP 5.1.0).
Fare riferimento alla funzione header() per ulteriori informazioni.
Nota:
Nota sulla versione di PHP
Le variabili autoglobali,
come $_SERVER, esistono
a partire da PHP » 4.1.0.
Un frammento di script di esempio che richiede l'autenticazione da parte del browser
su una pagina, potrebbe essere il seguente:
Example #1 Esempio di Autenticazione HTTP "Basic"
<?php
if (!isset($_SERVER['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';
exit;
} else {
echo "<p>Ciao {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>Hai inserito {$_SERVER['PHP_AUTH_PW']} come tua password.</p>";
}
?>
Example #2 Esempio di autenticazione HTTP "Digest"
Questo esempio illustra come implementare una autenticazione
Digest. Per maggiori dettagli vedere » RFC 2617.
<?php
$realm = 'Restricted area';
//user => password
$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).'"');
die('Text to send if user hits Cancel button');
}
// analisi della variabile PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Wrong Credentials!');
// generazione di una risposta valida
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] != $valid_response)
die('Wrong Credentials!');
// Ok, utente/password validi
echo 'Your are logged in as: ' . $digest['username'];
// funzione che analizza l'header http auth
function http_digest_parse($txt)
{
// protezione contro i dati mancanti
$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 ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
?>
Nota:
Note sulla compatibilitÃ
Fare molta attenzione quando si scrive codice per le intestazioni HTTP. Per ottenere la massima
compatibilità con tutti i client, la parola-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. I parametri di autenticazione devono
essere separati da virgole come si vede nell'esempio qui sopra.
Invece di stampare semplicemente PHP_AUTH_USER e
PHP_AUTH_PW, probabilmente si vorrà controllare
la validità dello username e della password.
Probabilmente 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.
A partire da PHP 4.3.0, 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 e modalità sicura è abilitato. Ciò nonostante, la variabile
REMOTE_USER può essere
usata per identificare un utente autenticato esternamente. Quindi, si può usare
$_SERVER['REMOTE_USER'].
Nota:
Nota sulla Configurazione
PHP usa la presenza di una direttiva AuthType
per determinare se viene utilizzata l'autenticazione esterna.
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".
Example #3 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($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Benvenuto: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Vecchio: " . htmlspecialchars($_REQUEST['OldAuth']);
echo "<form action='' method='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value=\"" . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "\" />\n";
echo "<input type='submit' value='Ri autentifica' />\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, prima di PHP 4.3.3, l'Autenticazione HTTP non funzionava
usando il server IIS di Microsoft e con la versione CGI di PHP a causa di una
limitazione di IIS. Al fine di farla funzionare in PHP 4.3.3+,
si deve modificare la configurazione di IIS "Directory Security".
Cliccare su "Edit" e selezionare solo
"Anonymous Access", tutti gli altri campi
devono essere lasciati deselezionati.
Un'altra limitazione è che se si usa il modulo IIS (ISAPI) e PHP 4, non si possono
usare le variabili PHP_AUTH_* ma, al contrario, la variabile
HTTP_AUTHORIZATION è disponibile. Per esempio, si consideri
il seguente codice: list($user, $pw) = explode(':',
base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
Nota:
Nota su IIS:
Al fine di fare funzionare la Autenticazione HTTP con IIS, la direttiva PHP
cgi.rfc2616_headers deve
essere impostata al valore 0 (il valore predefinito).
Nota:
Se è abilitato safe mode viene
aggiunto lo uid dello script al realm
dell'header WWW-Authenticate.