Uwierzytelnianie HTTP w PHP
Możliwe jest używanie
funkcji header() w celu wysłania do przeądarki komunikatu
"Wymagana autoryzacja". To powoduje wyświetlenie okna z polami:
użytkownik i hasło. Po wypełnieniu przez użytkownika tych pól, URL
zawierający skrypt PHP zostanie ponownie wywołany z ustawionymi
predefiniowanymi zmiennymi
PHP_AUTH_USER, PHP_AUTH_PW i
AUTH_TYPE zawierajÄ…cymi odpowiednio
nazwę użytkownika, hasło i typ autoryzacji. Zmienne te będą dostępne w
tablicy $_SERVER Obecnie obsługiwane są autoryzacje
typu "Basic" i "Digest" (od PHP 5.1.0). Więcej informacji można znaleŸć w opisie funkcji
header().
Przykładowy skrypt wymuszający autoryzację klienta:
Przykład #1 Uwierzytelnianie Basic HTTP
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Tekst do wysłania, jeśli użytkownik wciśnie przycisk Anuluj';
exit;
} else {
echo "<p>Hej {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>Twoje hasło to {$_SERVER['PHP_AUTH_PW']}.</p>";
}
?>
Przykład #2 Przykład uwierzytelnianie Digest HTTP
Ten przykład pokazuje jak zaimplementować proste umierzytelnianie
Digest HTTP. WiÄ™cej informacji znajduje siÄ™ w dokumencie » RFC 2617.
<?php
$realm = 'Zastrzeżona strefa';
//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('Tekst do wysłania kiedy użytkownik kliknie klawisz anuluj');
}
// analiza zmiennej PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Nieprawidłowe listy uwierzytelniające!');
// tworzenie prawidłowej odpowiedzi
$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('Nieprawidłowe listy uwierzytelniające!');
// ok, prawidłowa nazwa użytkownika i hasło
echo 'JesteÅ› zalogowany jako: ' . $data['username'];
// function to parse the http auth header
function http_digest_parse($txt)
{
// zabezpieczenie przeciwko brakujÄ…cym informacjom
$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('@(\w+)=(?:([\'"])([^\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;
}
?>
Informacja:
Kompatybilność
Należy uważać z linijkami dodawanymi do nagłówka HTTP. W celu zachowania maksymalnej
zgodności ze wszystkimi klientami, słowo Basic powinno zaczynać się dużą
literą "B", wartość realm powinna być otoczona cudzysłowami (nie apostrofami),
i dokładnie jeden znak odstępu powinien poprzedzać kod 401 w linii
HTTP/1.0 401. Parametry autoryzacyjne muszą być
oddzielone przecinkami jak pokazano to w przykładzie digest powyżej.
Zamiast wyświetlać wartość PHP_AUTH_USER i
PHP_AUTH_PW, jak to zrobiono w powyższym przykładzie,
zechcesz zapewne sprawdzić poprawność nazwy użytkownika i hasła. Na przykład
poprzez zapytanie do bazy danych lub odnalezienie użytkownika w pliku dbm.
Należy uważać na kapryśne przeglądarki Internet Explorer. Są wrażliwe na
kolejność wysyłanych nagłówków HTTP. Wysłanie nagłowka
WWW-Authenticate przed
HTTP/1.0 401 powinno rozwiązać problem.
Aby zapobiec sytuacji w której ktoś napisze skrypt
wykradający hasło wysłane tradycyjnym zewnętrznym mechanizmem,
zmienne PHP_AUTH nie będą ustawiane, jeśli dla danej strony
aktywna jest autoryzacja zewnętrzna
i tryb bezpieczny jest włączony. Bez względu na to,
REMOTE_USER może zostać użyte do zidentyfikowania
użytkownika autoryzowanego zewnętrznie Zatem, możesz użyć
$_SERVER['REMOTE_USER'].
Informacja:
Konfiguracja
Aby wykryć czy miała miejsce zewnętrzna autoryzacja, PHP sprwadza
obecność dyrektywy AuthType.
Powyższa metoda nie zapobiega jednak wykradaniu haseł do stron wymagających
autoryzacji przez kogoÅ›, kto na tym samym serwerze kontroluje strony nie
wymagajÄ…ce autoryzacji.
Zarówno Netscape Navigator jak i Internet Explorer opróżnią bufor
autoryzacji po otrzymaniu od serwera kodu 401. Można w ten sposób
wylogowanić użytkownika i zmusić go do ponownego wysłania nazwy użytkownika
i hasła. Tej metody można użyć do wylogowania użytkownika po określonym
czasie lub stworzenia przycisku "Wyloguj".
Przykład #3 Uwierzytelnianie HTTP z wymuszeniem przelogowania
<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Testowy system autoryzacji"');
header('HTTP/1.0 401 Unauthorized');
echo "Musisz podać poprawny login i hasło by wejść na tę stronę\n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Witaj: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Poprzednio: " . 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='Re Authenticate' />\n";
echo "</form></p>\n";
}
?>
Powyższa metoda nie jest wymagana przez autoryzację HTTP Basic,
więc nie można na niej polegać. Testy z przeglądarką
Lynx pokazały, że Lynx nie usuwa danych
o autoryzacji po odebraniu od serwera kodu 401, zatem przejście wstecz a następnie
do przodu otworzy stronę, chyba, że
wymagania co do danych autoryzacji zmieniły się. Użytkownik może jednak
użyć klawisza '_' by usunąc dane o autoryzacji.
Aby autoryzacja HTTP działała na serwerze Microsoft IIS z PHP w wersji
CGI musisz wyedytować "Bezpieczeństwo katalogów" w konfiguracji IIS.
Kliknij na "Edytuj" i zaznacz wyłącznie
"Anonimowy Dostęp", wszystkie inne pola
powinny pozostać nie zaznaczone.
Informacja:
Notatka IIS:
Aby Autoryzacja HTTP działała z IIS, dyrektywa PHP
cgi.rfc2616_headers musi
być ustawiona na 0 (domyślna wartość).
Informacja:
Jeśli włączony jest tryb bezpieczny,
uid skryptu jest doklejany do pola realm nagłówka
WWW-Authenticate.