Capa de seguridad en PHP

  • Por
Este capítulo nos explicará el funcionamiento del módulo de seguridad.
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();
}
?>

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

Jorge Villegas

17/3/2003
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.

armando rodriguez

20/5/2003
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");
}

ZarDonkan

28/5/2003
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

Patricio Villarroel

03/8/2003
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

Joaquín Delgado

15/9/2003
Quiciera saber como quedaria entonces "seguridad.php" ya que el que esta en el ejemplo no es tan seguro. Gracias por la ayuda

Hugo De Jesus

25/2/2004
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!!!

jaime tan

25/2/2004
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?

Juano

05/4/2004
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.

Ing Jose Velasquez

02/6/2004
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.

OSKAR

18/6/2004
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

wintermute

18/1/2005
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.

John Sotelo

18/5/2006
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

Tonini

09/11/2006
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

icio

22/11/2006
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!

Upatseb

18/1/2007
Sobre la solución propuesta por patricio de comprobar si existe la variable autentificado decir que a mi me ocurre que la primera vez que intento logear nunca encuentra la variable y la segunda ya sí, no se porqué, ¿alguna idea?.

Fernando

13/5/2007
pero la cosa es muy distinta... si el pasword y el usuario .. lo sacan de una base de datos .. para despues compararlo con lo q ingreso el usuario .. o no? .. bueno ... a mi me parece un muy buen ejemplo .. para empezar .. nada q ver q digan q esta malo .. o q esperaban.. q sea una barrera de seguridad impenetrable ... las mejores cosas .. SON MAS COMPLICADAS VIEJOS... suerte ... y metanle ganas .... CHAUSITO!!

Fernando

13/5/2007
Jaj ja sabes muchacho, este articulo es muy serio .. creo q deberias entender mejor las variables de tipo session antes de poner tu comentario .. lo q dices se podria hacer con variables tipo get y post .. pero no con las de tipo session, ya que no basta con ponerlas en la barra de direcciones, sino q la pag verifica la existencia de las variables antes de dejarte entrar, tal ves te confundiste ... pq solo podes ahcer eso mientras ya pasaste la etapa de verificacion, pq una ves q cierras las varibles de session, no podes acceder por la barra de direcciones, asi q mucho ojo con los comentarios a esta pag :D saludos!! y mucha suerte a todos !!!

Ricardo Sánchez

16/11/2007
Buenas Tardes, tengo tiempo búscando la manera de leer el Código de Acceso desde la pantalla Principal de Windows para guardarlo en una variabla dentro del código PHP que me permite la validación y aún no he conseguido cuál es la Instrucción que me permita obtener el Código de accseso a Windows de Un Usuario. Mucho agradeceré si me pueden ayudar a solventar el problema.

conocido5

01/3/2008
estuve provando el escript y me funciono perfectamente, inclusive gracias por la información.

Luis Miguel Camacho

18/3/2008
El mayor fallo de seguridad que le veo es que desde Firefox la capa de seguridad se la salta.

EDMO

24/11/2008
buenas yo tengo una duda porque yo puedo tener mi pagina de seguridad pero al escribir la direccion url de la pagina a la q deseo acceder entro sin problemas.. precisamente eso es lo que deseo evitar

Javier

06/6/2009
CAPA DE SEGURIDAD
Buen dia, estoy aprendiendo PHP, quisiera saber si mi siguiente script se encuentra bien codificado y solo para saber si podria implementarse para multiusuario

<?php
include("configuracion.php");

$users = explode("|",$Config);

$usid = "noencontrado";
$uspswd = "noencontrada";

for ($i=0;$i<=count($users)-1;$i++){

$userandpasswd = explode(":",$users[$i]);
$usid = trim($userandpasswd[0]);
$uspswd = trim($userandpasswd[1]);

if ($usid == "" || strlen($usid) == 0){
$usid = "noencontrado";
header("Location: index.php?errorusuario=si");
exit();
}

if ($uspswd == "" || strlen($uspswd) == 0){
$uspswd = "noencontrada";
header("Location: index.php?errorusuario=si");
exit();
}

if ($_POST["usuario"] == $usid && $_POST["contrasena"] == $uspswd){
//usuario y contraseña válidos
//defino una sesion y guardo datos
session_start();

$_SESSION["autentificado"]= "SI";

header ("Location: aplicacion.php");
exit();

}else{
$usid = "noencontrado";
$uspswd = "noencontrada";
}
}


if ($usid == "noencontrado" || $uspswd == "noencontrada")
header("Location: index.php?errorusuario=si");
?>


teniendo el script configuracion los usuarios y passwords de la siguiente forma
$Configuracion = "usuario1:pass1|usuario2:pass2|usuario3:pass3"; y asi sucesivamente bueno saludos y thanks :)

Metafaniel

25/8/2009
Obscurecer las URLs
Obviamente como comenten este sencillo script tiene posible huecos, pero como comenta su autor, la idea es dar una idea funcional mediante PHP de la seguridad, pero sin excesivo detalle.
Ya buscando mejorar la seguridad y dejar practicamente imposible siquiera saber el URL de las páginas seguras, considero muy importante saber "obscurecer" las URLs, que no es otra cosa que convertir:
www.desarrolloweb.com en http://54821354@761237623434%415245%1315235% (por poner un ejemplo inventado, para que dé la idea)

Si quieren saber el detalle de cómo lograr obscurecer las URLs de esta manera y, por tanto, mejorar la seguridad, chequen este interesante artículo (en inglés)

http://www.pc-help.org/obscure.htm

angel

06/12/2009
muy importante
porque no colocas php en:

<? php

?>

Leo

05/2/2012
duda
debo de crear otra pagina o ese codigo lo inserto en una pagina ya echa

EVELIN

26/5/2014
ayuda URGENTE
Quisiera saber como encripto la url de mi sistema creado en php, es decir que no pueda modificarla ni ser alterada. Me lo solicitan y soy nueva en esto.