Autenticación HTTP con PHP

Es posible usar la función header() para enviar un mensaje “Authentication Required” al navegador del cliente causando que se abra una ventana para ingresar usuario y password. Una vez se ha llenado el usuario y password, la URL contenida dentro del script PHP será llamada nuevamente con las variables predefinidas PHP_AUTH_USER, PHP_AUTH_PW, y AUTH_TYPE puestas por el nombre del usuario, password y el tipo de autenticación respectivamente. Esas variables predefinidas son encontradas en los arrays $_SERVER y $HTTP_SERVER_VARS. Ambos métodos de autenticación “Basic” y “Digest” (desde PHP 5.1.0) son soportados.

Nota: Nota de la versión de PHP

Superglobals, como $_SERVER, están disponibles en PHP » 4.1.0.

Un fragmento de ejemplo de un script el cual podría forzar la autenticación en una página es el siguiente:

Ejemplo #1 Ejemplo de Autenticación HTTP Basic

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Texto a enviar si el usuario pulsa el botón Cancelar';
exit;
} else {
echo "<p>Hola {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>Tu ingresaste {$_SERVER['PHP_AUTH_PW']} como tu password.</p>";
}
?>

Ejemplo #2 Ejemplo de Autenticación HTTP Digest

Este ejemplo muestra como implementar un script PHP de autenticación Digest.

<?php
$realm = 'Area restringida';

//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('Texto a enviar si el usuario pulsa el botón Cancelar');
}

// analiza la variable PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Datos Erroneos!');

// Generando una respuesta 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('Datos Erroneos!');

// ok, usuario & password validos
echo 'Estas logueado como: ' . $data['username'];

// function to parse the http auth header
function http_digest_parse($txt)
{
// proteger contra datos perdidos
$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: Nota de Compatibilidad

Hay que ser cuidadoso cuando se programan las líneas del HTTP header. Para garantizar la mayor compatibilidad con todos los clientes, la palabra “Basic” debe ser escrita con mayúsculas “B”, el string real debe ser encerrado en comillas dobles (no simples), y exactamente un espacio debe preceder el código 401 en la línea del header HTTP/1.0 401. Los parámetros de autenticación deben ser separados por comas como se vió en el ejemplo resumido anterior.

En lugar de imprimir simplemente PHP_AUTH_USER y PHP_AUTH_PW, como se hizo en el ejemplo anterior, se debería chequear el usuario y password para validar. Tal vez enviando una consulta a una base de datos, o buscando el usuario en un archivo dbm.

Cuidado con errores con el Internet Explorer. Parece ser muy quisquilloso con el orden de los headers. Enviando el header WWW-Authenticate antes que el header HTTP/1.0 401 parece ser un truco por ahora.

A partir de PHP 4.3.0, en orden de prevenir que alguien escriba un script el cual revele el password para una página que fué autenticada con un mecanismo externo tradicional, las variables PHP_AUTH no deberán ser colocadas si la autenticación externa esta habilitada para esa página en particular y si safe mode esta habilitado. Independientemente, REMOTE_USER puede ser usado para identificar al usuario autenticado externamente. Así, se podrá usar $_SERVER[‘REMOTE_USER’].

Nota: Nota de configuración

PHP usa la presencia de una directiva AuthType para determinar si una autenticación externa esta en uso.

Nótese, sin embargo, que lo anterior no impide que alguien quien controle una URL no autenticada pueda robar passwords de URL’s autenticadas en el mismo servidor.

Tanto Netscape Navigator e Internet Explorer borrarán el caché de la ventana de autenticación del navegador local después de recibr una respuesta 401. Esto puede “desloguear” efectivamente a un usuario, forzandolo a reingresar su usuario y password. Algunas personas usan esto para “hacer esperar” logueos, o proveer un botón de “deslogueo”.

Ejemplo #3 Ejemplo de Autenticación HTTP forzando a un nuevo usuario/password

<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "Debes ingresar un login ID y password validos para accesar a este recurso\n";
exit;
}

if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Bienvenido: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Anterior: " . 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";
}
?>

Este comportamiento no es requerido por la autenticación HTTP Basic estandar, así que se debería depender de esto. Probando con Lynx mostrará que Lynx no limpia las credenciales de autenticación con una respuesta 401 del servidor, asi que presionando back y luego forward abrirá el recurso nuevamente si estos no han cambiado. Sin embarogo, el usuario puede presionar la tecla ‘_’ para limpiar su información de autenticación.

También notese que hasta PHP 4.3.3, la autenticación HTTP no trabajaba usando Microsoft IIS con la versión CGI de PHP, una limitación de IIS. Para hacer funcionar PHP 4.3.3 o mayor, se debe editar la configuracion de IIS “Directory Security“. Hacer click en “Edit” y solo chequear “Anonymous Access“, todos los demas campos dejarlos sin chequear.

Otra limitación si se esta usando el módulo IIS (ISAPI) y PHP 4, no se debería usar las variables PHP_AUTH_* pero en su lugar, la variable HTTP_AUTHORIZATION esta disponible. Por ejemplo, considerar el siguiente código: list($user, $pw) = explode(‘:’, base64_decode(substr($_SERVER[‘HTTP_AUTHORIZATION’], 6)));

Nota: Nota de IIS:
Para que funcione la Autenticación HTTP con IIS, la directiva de PHP cgi.rfc2616_headers debe ser configurada a 0 (el valor por defecto).

Nota:

Si safe mode esta habilitado, el uid del script es agregado a la parte del reino del header WWW-Authenticate.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *