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
nell'array $_SERVER. 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.
Un frammento di script di esempio che richiede l'autenticazione da parte del browser su una pagina, potrebbe essere il seguente:
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>"; } ?>
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; } ?>
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.
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".
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.
Al fine di far funzionare l'Autenticazione HTTP usando il server IIS con la versione CGI
di PHP 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.
0 (il valore predefinito).