Uwierzytelnianie HTTP jest obsługiwana przez PHP tylko wtedy, gdy PHP pracuje
jako moduł Apache'a, nie jest dostępna w trybie CGI. W skrypcie można użyć
funkcji header() by wysłać do przeglądarki komunikat
"Wymagana autoryzacja", co spowoduje wyświetlenie okienka 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
tablicach $_SERVER oraz
$HTTP_SERVER_VARS. Obecnie obsługiwane są autoryzacje
typu "Basic" i "Digest" (od PHP 5.1.0). Więcej informacji znajdziesz w opisie funkcji
header().
Przykładowy skrypt wymuszający autoryzację klienta:
Przykład 34-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 34-2. Przykład uwierzytelnianie Digest HTTP
Ten przykład pokazuje jak zaimplementować proste umierzytelnianie
Digest HTTP. Po więcej informacji przeczytaj 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();
preg_match_all('@(\w+)=([\'"]?)([a-zA-Z0-9=./\_-]+)\2@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) { $data[$m[1]] = $m[3]; unset($needed_parts[$m[1]]); }
return $needed_parts ? false : $data; } ?>
|
|
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'].
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 34-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: {$_SERVER['PHP_AUTH_USER']}<br />"; echo "Poprzednio: {$_REQUEST['OldAuth']}"; echo "<form action='{$_SERVER['PHP_SELF']}' METHOD='post'>\n"; echo "<input type='hidden' name='SeenBefore' value='1' />\n"; echo "<input type='hidden' name='OldAuth' value='{$_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 typu "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.
Zwóć uwagę, że do wersji PHP 4.3.3, Autoryzacja HTTP nie działała
na serwerze Microsoft IIS z PHP w wersji CGI z powodu
ograniczeń IIS. Aby zmusić go do działania w PHP 4.3.3+
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.
Inne ogranicznie jest jeśli używasz modułu IIS (ISAPI) i PHP 4, nie możesz
wtedy użyć zmiennych PHP_AUTH_* ale zamiast nich,
dostępna jest zmienna HTTP_AUTHORIZATION. Na przykład
rozważ następujący kod: list($user, $pw) = explode(':',
base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
Notatka IIS::
Aby Autoryzacja HTTP działała z IIS, dyrektywa PHP
cgi.rfc2616_headers musi
być ustawiona na 0 (domyślna wartość).
Notatka:
Jeśli włączony jest tryb bezpieczny,
uid skryptu jest doklejany do pola realm nagłówka
WWW-Authenticate.