Capa de seguridad en PHP

Valoración del artículo:
Este capítulo nos explicará el funcionamiento del módulo de seguridad.
Publicado: 19/12/02
Atención: Contenido exclusivo de DesarrolloWeb.com. No reproducir. Copyright.
Este archivo, en nuestro caso llamado seguridad.php, se encargará de dotar seguridad a toda la aplicación de acceso restringido. La técnica que vamos a utilizar es incluirlo al principio de todas las páginas que queramos que permitan un acceso restringido.

El módulo de seguridad, incluido al principio de cada archivo, realizará las comprobaciones oportunas y actuará permitiendo ver el archivo o denegando su visualización dependiendo de dichas comprobaciones.

Dependiendo del nivel de seguridad que deseemos implementar, la creación de este archivo puede ser más o menos complicada. Como no deseo complicar en un principio los scripts, esta versión resultará bastante sencilla.

Lo único que haré será recuperar la variable de sesión donde guardo si ese usuario ha sido autentificado o no. Luego se comprueba esa variable para saber si se ha autentificado el usuario o no, realizando estas acciones:

Si no se había autentificado, redirijo al navegador a la página que tiene el formulario de autentificación. Además, salgo del script PHP, con lo que la página deja de ejecutarse y el resto no se verá. Sólo se mandará al navegador la redirección con lo que el navegador se moverá la formulario y será imposible ver nada en la página segura.

Si se había autentificado, no hago nada. Ni tan siquiera trato este caso, de modo que se seguiría ejecutando la página con el contenido que correspondiese. No hay que olvidar que este archivo de seguridad se va a ejecutar como un include al principio de todos los archivos de la aplicación restringida, lo que significa que, si no se hace nada, se seguiría mostrando la página donde este archivo está incluido.

El código se puede ver a continuación:

<?
//Inicio la sesión
session_start();

//COMPRUEBA QUE EL USUARIO ESTA AUTENTIFICADO
if ($_SESSION["autentificado"] != "SI") {
    //si no existe, envio a la página de autentificacion
    header("Location: index.php");
    //ademas salgo de este script
    exit();
}
?>

Comentarios
Fueron enviados 23 comentarios al artículo
9 comentarios no revisados
14 comentarios revisados:
Por: Jorge Villegas
17/3/03
OJO.

Este capítulo de autentificación es muy simple y no es segura su utilización. Por tanto, no es aplicable en ningún caso. Sólo ilustra la posible metodología a seguir.

Me fundamento en lo siguiente:

Se puede entrar directamente a la aplicación sin digitar el nombre de usuario y contraseña, digitando en la barra de direcciones lo siguiente:

www.desarrolloweb.com/.../autentificacion-php/aplicacion.php?autentificado=SI

Y LISTO, ESTAS DENTRO.

No es nada asomborso darse cuenta de ello. Debería haber más seriedad en la publicación de los artículos.

RESPUESTA

Tienes toda la razón, este manual práctico, por lo menos en sus primeros capítulos, sólo persigue mostrar una metodología y una posible forma de atacar el problema de la autentificación, pero no ofrecer un sistema a prueba de intrusos.

En nuestro afan por hacer fácilmente comprensibles los scripts, para ir complicándolos poco a poco y aprender paso a paso, se nos ha escapado un error que has podido encontrar muy lógicamente, pues es el error típico. Es el "error de libro" que se utiliza para explicar como hacer un sistema seguro.

De todos modos, hemos modificado los scripts para que, manteniendo la misma sencillez, no se pueda acceder tal como planteas en este comentario.

Ahora, en capítulos sucesivos de este manual y tal como pretendíamos originalmente, seguiremos implementando mejoras en el acceso restringido para que cada vez quede más blindada nuestra aplicación contra accesos no permitidos.

Códigos que había antes, donde se puede apreciar el error

Para el que le interese, mostramos a continuación el código que había originalmente y que, efectivamente, tenía un grave agujero de seguridad y además muy básico.

//TOMO VARIABLES DE SESION SOBRE LA AUTENTIFICACION
session_register("autentificado");

//COMPRUEBA QUE EL USUARIO ESTA AUTENTIFICADO
if ($autentificado != "SI") {
//si no existe, envio a la página de autentificacion
header("Location: index.php");
//ademas salgo de este script
exit();
}
?>

La explicación de lo que pasaba es la siguiente: en este código se accedía a la variable que guarda el control sobre si se había autentificado o no (Variable $autentificado) directamente, sin tener en cuenta que es una variable de session.

Como en nuestro servidor está activa la opción register_globals, la variable pasada por la URL para burlar el mecanismo de seguridad se autodeclara en la página. Entonces, al acceder a la variable $autentificado para saber si está o no autentificado el usuario, se tomaría el valor de la variable de sesion y, si no está por no estar autentificado el usuario, se tomaría el valor de la variable pasada por la URL que justamente guarda el dato del cual la capa de seguridad entiende que sí está autentificado.

Muchas gracias por el comentario y para todos los demás, atentos a próximos capítulos para tratar este tema en profundidad.

Por: armando rodriguez
20/5/03
Realmente la observación de pasar por la url el valor de la variable es bastante hipotético, no se puede saber de antemano cual es el nombre de la variable que utilizaremos.
Tal vez adivinando si, pero si utilizamos una descripción para la variable un poco mas larga no creo que se adivine tan fácilmente, y si además la variable que declaramos es un vector, como se podra pasar por la url ese valor

Ejemplo
session_start();
session_register("SEGURIDAD");

if ($SEGURIDAD["libre"] == “NO'')
{
header("Location: login.php");
}
Por: ZarDonkan
28/5/03
La solucion al problema de si es segura o no es aplicar en el archivo aplicacion la siguiente variable

if ($_SESSION["autentificado"] == "SI") {

Suerte en su camino
Por: Patricio Villarroel
03/8/03
Después de mandar varias consultas, y de intentar de muchas formas, al recurrir al manual de PHP de www.php.net pude resolver el gran error de esta aplicación. Quienes hayan realizado este sistema de autentificación en sus casas, habrán notado que todo funciona excelente, hasta que se nos ocurre acceder al fichero "aplicacion.php" (artículo "Archivos de la aplicación con acceso restringido en PHP") sin ingresar el user y el password, pues se nos frena el header con los siguientes mensajes:

Notice: Undefined index: autentificado in c:\inetpub\wwwroot\taller\autentificacion\seguridad.php on line 6

Warning: Cannot modify header information - headers already sent by (output started at c:\inetpub\wwwroot\taller\autentificacion\seguridad.php:6) in c:\inetpub\wwwroot\taller\autentificacion\seguridad.php on line 8

Estos errores tienes sus explicaciones, y soluciones (que mucho me costó encontrar). El Notice se produce porque $_SESSION["autentificado"], al no venir de "control.php" no está definido, y por tanto no existe. Entonces php manda un error porque la variable está indefinida. Pero como un if pide información, el header se inactiva simplemente porque no puede haber transferencia de datos antes de un header (ver el manual de referencia de php). Entonces manda el segundo error.

Entonces, habría que encontrar una instrucción que detectara si existe o no un valor para $_SESSION["autentificado"], cosa que no mande el Notice, y cambiar el header por otra instrucción parecida que permita el intercambio de variables antes de que haga su aparición. Yo conseguí esto de la siguiente forma (cambia todo el código de seguridad.php):

<?
session_start();
$var = isset ($_SESSION["autentificado"]) ;
if ($var == FALSE) {
    include ("http://localhost/taller/autentificacion/index.php?errorusuario=noreg");
    exit(); }
if ($var == TRUE AND $var != "SI") {
    include ("http://localhost/taller/autentificacion/index.php?errorusuario=noreg");
    exit(); }
?>


La instrucción isset determina si la variable $_SESSION["autentificado"] está definida. Si lo está, $var devuelve TRUE, y si no lo está (no existe en nuestro caso) devuelve FALSE. Luego se indica que si $var es FALSE, incluya el fichero index.php, con la variable errorusuario=noreg (algo que inventé, que en vez de decir "datos incorrectos" cuando errorusuario=si, diga "Debe autentificarse para ver esta página"). Pero ojo, que necesita la URL completa, por cambiarse el header por include. En mi ejemplo, la URL que allí aparece es la que uso yo y no tiene por qué ser igual a la que usen otros.
Luego es necesario definir qué hacer si $_SESSION["autentificado"] tiene un valor cualquiera que no sea "SI". Si lo dejamos así, php asume que el valor cualquiera que tenga está correcto, e inicia sesión, dejando un agujero de seguridad. Esto se resuelve con if ($var == TRUE AND $var != "SI"), que realiza la instrucción sólo cuando $_SESSION["autentificado"] existe pero es distinta a "SI". En caso contrario (si $_SESSION["autentificado"] = "SI") inicia sesión, que es lo que queríamos.
El usar include sólo agrega la página que tiene entre paréntesis, tal como un afluente aporta sus aguas a un rio. Si ingreso algunos datos a mostrar antes del include, o después, estos aparecerán, pues el include no actúa redireccionando, sino agregando.

Espero que se haya entendido, porque hasta a mí me costó entender lo que hice... jajaja.

Patricio
Por: Joaquín Delgado
15/9/03
Quiciera saber como quedaria entonces "seguridad.php" ya que el que esta en el ejemplo no es tan seguro. Gracias por la ayuda
Por: Hugo De Jesus
25/2/04
A me sucedio lo mismo, la seguridad no era tan segura, detecte que habia un hueco de seguridad y trate de entender la logica del codigo. Efectivamente la variable de sesion la podias brincar, pero se soluciona con el siguiente codigo el cual revisa si esta declarada la variable de sesion si no lo esta, la retoma en otra variable si no asigno una negacion y en el condicional redirecciono a una pagina con un mensaje de negacion, en este caso con incrustaciones de java porque como manejo frames solo asi es posible, pero ustedes pueden resumir la redireccion en una sola linea de codigo con un header.

<?php
session_start();

if (isset($_SESSION["validado"])) {
    $validado = $_SESSION["validado"];
} else {
    $validado = "N";
}

if ($validado == "N") {
   //header("Location: index.php");
    echo "<script language=\"JavaScript\" type=\"text/javascript\">\n";
    echo "<!--\n";
    echo "top.location.href = 'denied.php';\n";
    echo "//-->\n";
    echo "</script>\n";
    exit();
}
?>

Arriba el Open Source!!! Linux!!!
Por: jaime tan
25/2/04
TAL vez la variable de paso de sesion para confimacion sea aleatoria con el MD5 y el valor tambien; que en el momento se almacenaria en la base de datos para luego ser recuperado...
Cuando se cierre Cesion se borran los datos... De esta forma la variable nunca va ser la misma???
Creen asi podria tener mas seguridad , no?
Por: Juano
05/4/04
La solucion es tan simple como almacenar en una variable de sesion el ID de Session de PHP cuando el usuario hace el login. Y luego en el resto de páginas comprobar que el valor de esa variable coincide con el SID activo para decidir si se muestra el contenido o se denega el acceso.

Salu2.

Por: Ing Jose Velasquez
02/6/04
Esta bien, pero como valido que yo no entre 2 veces al sitio, osea si estoy dentro no tengo porque volver a entrar. Es lo que usa hotmail para validar a los usuarios. Si alguien sabe solucionar eso que porfavor lo publique.
Saludos desde Chile.
Por: OSKAR
18/6/04
Buenas...

A mi el ejemplo me parece cojonudo. Estoy empezando con esto y no veo ningún error de los k hablais. Yo cambié la variable autentificado por otra e intenté entrar poniendo lo k decis de aplicacion.php?variable=SI y ni flores, no me dejó entrar. Además, como bien se respondió, la persona k kiera meterse ilegalmente, deberá conocer el nombre de la variable k se le ha puesto al archivo control.php para poder entrar.

Gracias por el ejemplo y por los comentarios.
saludos

Por: wintermute
18/1/05
Sobre el último comentario acerca del script, y teniendo en cuenta la fecha en qué está publicado, podemos suponer que tenga una versión de php en su servidor con la directiva register_globals en off, por lo que, aunque le pases por url una variable con el mismo nombre que la variable de sesión, no la registrará como variable corta.
Por: John Sotelo
18/5/06
Concuerdo con todos ustedes en el uso de sesiones, pero a mi modesto parecer se agregaria mayor seguridad si a la sesion le asignamos nombres de variables mas complejas y en un ambiente o ventana sin que se muestre los link y la barra de estado, y ademas si se puede evitar el que se queden grabadas las URL's de las paginas del sistema
Por: Tonini
09/11/06
la verdad,esta demasiaod bueno,pese a su simplesa.
pero me gustaria saber como manteniendo lo mas parecido posible todo,poner mas usuarios y contraseñas.
saludos
Por: icio
22/11/06
A mi me resulto muy seguro hacer que la variable de sesión obtenga un valor randomizado mediante la funcion rando() de una tabla en MySQL (por ej, permiso) que guarda `n` posibles valores. Que alguien me diga cómo hace para averiguar el valor de la variable...ja!

Manuales relacionados
Categorias relacionadas
El autor
Lectura recomendada
Compra este libro en Agapea, la librería urgente a domicilio.
Últimas noticias
Alojados en el grupo