Forum und email

HTTP hitelesítés PHP-vel

A HTTP hitelesítési (authentication) funkciók csak akkor elérhetőek PHP-ben, ha az Apache modulként fut, bár régebben ez a CGI módú használat során is működött, azonban ez a lehetőség már megszűnt. Az Apache modulként futó PHP esetében a header() függvényt kell használni arra, hogy egy "Authentication Required" üzenetet küldjön a kliens böngészőnek, aminek hatására az egy Username/Password bemeneti ablakot nyit meg a felhasználó számára. Ha a látogató kitöltötte a username és password mezőket, az URL, ami a PHP szkriptre mutat, ismét meghívásra kerül, és rendelkezésre állnak a PHP_AUTH_USER, PHP_AUTH_PW és a AUTH_TYPE változók, amik a felhasználói név, jelszó és azonosítási típus értékeket tartalmazzák értelemszerűen. Mind a "Basic", mind a "Digest" (PHP 5.1.0 óta) azonosítási típus támogatott. További információt a header() függvény dokumentációjában találsz.

Note: PHP verziókhoz kötödő megjegyzés Az autoglobális változók, mint például a $_SERVER, a PHP » 4.1.0 változatától elérhetőek. PHP 3-ban helyette a HTTP_SERVER_VARS használható.

Egy egyszerű példa PHP szkript, ami kliens azonosítást vált ki:

Example#1 HTTP azonosítási példa (Basic)

<?php
  
if( !isset($_SERVER['PHP_AUTH_USER']) ) {
    
header('WWW-Authenticate: Basic realm="Azonosítsd magad!"');
    
header('HTTP/1.0 401 Unauthorized');
    echo 
'Ez jelenik meg, ha a Cancel gombot nyomja a felhasználó';
    exit;
  } else {
    echo 
"<p>Helló {$_SERVER['PHP_AUTH_USER']}.</p>";
    echo 
"<p>A megadott jelszavad: {$_SERVER['PHP_AUTH_PW']}.</p>";
  }
?>

Example#2 HTTP azonosítási példa (Digest)

Az alábbi példamutatja be, hogy lehet összeállítani egy Digest típusú HTTP azonosítást végző szkriptet. A dologról bővebb információkat az » RFC 2617 leírásában találsz.

<?php
$realm 
'Ide csak úgy ben nem lépsz!';

// felhasználónév => jelszó
$felhasznalok = array('admin' => 'mypass''guest' => 'guest');


if (!isset(
$_SERVER['PHP_AUTH_DIGEST'])) {
    
header('HTTP/1.1 401 Unauthorized');
    
header('WWW-Authenticate: Digest realm="'.$realm.
           
'" qop="auth" nonce="'.uniqid().'" opaque="'.md5($realm).'"');

    die(
'Ez a szöveg jelenik meg, ha a túloldalon Mégsemet (Cancel) nyomtak');
}

// A PHP_AUTH_DIGEST-ben kapottak analizálása
preg_match('/username="(?P<username>.*)",\s*realm="(?P<realm>.*)",\s*nonce="(?P<nonce>.*)",\s*uri="(?P<uri>.*)",\s*response="(?P<response>.*)",\s*opaque="(?P<opaque>.*)",\s*qop=(?P<qop>.*),\s*nc=(?P<nc>.*),\s*cnonce="(?P<cnonce>.*)"/'$_SERVER['PHP_AUTH_DIGEST'], $digest);

if (!isset(
$felhasznalok[$digest['username']]))
    die(
'A felhasználónév nem megfelelő!');


// generate the valid response
$A1 md5($digest['username'] . ':' $realm ':' $felhasznalok[$digest['username']]);
$A2 md5($_SERVER['REQUEST_METHOD'].':'.$digest['uri']);
$valid_response md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);

if (
$digest['response'] != $valid_response)
    die(
'Az azonosítás sikertelen!');

// minden oké, jó a felhasználónév / jelszó páros
echo 'Beléptél ezen a néven: ' $digest['username'];

?>

Note: Megjegyzés Vigyázni kell a HTTP fejlécek írásakor! A maximális kompatibilitás eléréséhez a "Basic" kulcsszót nagy B betűvel kell kezdeni, a "realm" részt mindenképpen idézőjelbe (és nem aposztrófok közé) kell tenni! Végül pontosan egy szóközt hagyj ki a "401" előtt a "HTTP/1.0 401" fejléc sorban.

Egy valós esetben persze nem a $PHP_AUTH_USER és $PHP_AUTH_PW kiírása az elérni kívánt cél, így általában a felhasználói név és jelszó ellenőrzése következik. Természetesen lehetőség van ezt egy adatbázis lekérdezéssel megoldani, vagy egy dbm fájlban utánanézni a szükséges adatoknak.

Figyelj az Internet Explorer böngészők hibáira, ezek nem fogadják el tetszőleges sorrendben a HTTP fejléceket. A tesztek azt mutatják, hogy a WWW-Authenticate elküldése a HTTP/1.0 401 előtt megoldja a problémát.

Mivel a hagyományos HTTP azonosítás során a PHP 4.3.0-ás változatától kezdődően a jelszó rejtett az elért szkript előtt, a PHP nem állítja be a PHP_AUTH változókat ha az adott file-ra ha hagyományos azonosítás is engedélyezett és a ??? bekapcsolt állapotban van. Így nem deríthető ki a user jelszava. Ebben az esetben a REMOTE_USER változó tartalmazza a már azonosított felhasználó nevét, azaz $_SERVER['REMOTE_USER']-ként férhetünk hozzá.

Note: Beállítási megjegyzés A PHP az AuthType direktíva megléte alapján dönti el, hogy rajta kívülálló azonosítás történik-e.

Vedd észre, hogy ez nem küszöböli ki azt a problémát, hogy más nem azonosítás-köteles URL címeken lévő szkriptek ugyanazon a szerveren megszerezzék a jelszavakat az azonosított URL-ekről.

A Netscape Navigator és Internet Explorer böngészők törölni fogják a böngésző adott oldalhoz tartozó azonosítási tárát (authentication cache), amennyiben egy 401-es szerver üzenetet kapnak. Ez gyakorlatilag kilépteti a user-t, ami azt jelenti, hogy legközelebb ismét meg kell adnia a nevét és jelszavát. Időnként ezt arra használják, hogy lejárati időt rendelve a belépésekhez egy idő után megszüntessék azokat, vagy egy kilépés gombot biztosítsanak.

Example#3 HTTP azonosítási példa, ami új nevet és jelszót kér

<?php
  
function azonositas() {
   
header"WWW-Authenticate: Basic realm=\"Azonosítási Rendszer Teszt\"");
   
header"HTTP/1.0 401 Unauthorized");
   echo 
"Érvényes nevet és jelszót kell megadnod, hogy elérd ezt a szolgáltatást!\n";
   exit;
  }
  if (!isset(
$_SERVER['PHP_AUTH_USER']) ||
      (
$_POST['SeenBefore'] == && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
   
azonositas();
  }
  else {
   echo 
"<p>Üdv néked, {$_SERVER['PHP_AUTH_USER']}<br>";
   echo 
"Régebben: {$_REQUEST['OldAuth']}";
   echo 
"<form action='{$_SERVER['PHP_SELF']}' method='post'>\n";
   echo 
"<input type='hidden' name='JartMarItt' value='1' />\n";
   echo 
"<input type='hidden' name='RegiUser' value='{$_SERVER['PHP_AUTH_USER']}' />\n";
   echo 
"<input type='submit' value='Újraazonosítás' />\n";
   echo 
"</form></p>\n";
  }
?>

A HTTP Basic azonosítási standard nem követeli meg ezt a viselkedést a böngészők részéről, tehát ne építs rá! Lynx-el végzett tesztek azt mutatták, hogy a Lynx nem törli az azonosítási bizonyítványokat a 401-es szerver válasz hatására, tehát egy back és forward lépéssel ismét megnyílik az oldal, feltéve, hogy az azonosítási feltételek nem változtak. Ellenben a felhasználó megnyomhatja a '_' billentyűt, hogy törölje az azonosítási információkat.

Szintén fontos megjegyezni, hogy ez a módszer nem vezet eredményre (A PHP 4.3.3 változatáig bezárólag), ha Microsoft IIS szervert használsz CGI módú PHP-val, az IIS korlátai miatt. Ahhoz, hogy ezt a PHP 4.3.3 változatától kezdve használhasd, bele kell kicsit nyúlni az IIS beállításaiba. A "Directory Security" beállításainál kattints az "Edit" gombra és csak az "Anonymous Access"-t hagyd bekapcsolva.

Egy másik korlátozása az IIS (ISAPI) modulnak, hogy a PHP_AUTH_* változók nem kapnak értéket. Helyette a HTTP_AUTHORIZATION áll rendelkezésre. Egy kis példakód ötletképpen: list($user, $pw) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));

Note: Megjegyzés az IIS kapcsán: Ahhoz, hogy a HTTP azonosítás működjn IIS alatt, 0-ra kell állítani a cgi.rfc2616_headers PHP konfigurációs direktíva értékét (ez az alapértelmezett értéke).

Note: Ha safe mode be van kapcsolva, akkor a WWW-Authenticate fejléc realm részéhez a szkript UID-ja is hozzáadódik. the header.