Cómo generar sesiones en PHP de forma segura

Inicio/Blog de ciberseguridad/Cómo generar sesiones en PHP de forma segura

Buscar por:

Cómo generar sesiones en PHP de forma segura

Al hacer una auditoría de seguridad web contra un sistema, uno de los frentes de ataque es la gestión de sesiones. La posibilidad de que alguien pueda suplantar la identidad de otro usuario, o interactuar con módulos de la aplicación sin estar autenticado puede provocar dolores de cabeza a los desarrolladores y a la organización.

Existen varios aspectos complejos en la gestión de sesiones, pero todo esto se empieza a simplificar si centralizamos en un único módulo todo el código encargado de esta gestión. Una vez definido el fichero que hará de repositorio central de las funciones de gestión de sesiones, es necesario incluir dicho módulo en todas nuestras páginas web.

Dependiendo de nuestro framework de desarrollo, la inclusión de dichas funciones las realizaremos a través de métodos “autoload”, a través de require() / include(), o de otros mecanismos habilitados para la carga de módulos.

Nuestro código debe garantizar que se inicialice una sesión en cada petición HTTP . Vamos a usar para este ejemplo el fichero security.php que será cargado por todos los módulos de la aplicación web a través de los métodos mencionados en el parrafo anterior.

/* Inicializamos la sesion*/
session_start();

 

Si queremos asegurarnos de la privacidad de nuestras páginas, y que estas indiquen que no deben ser cacheadas por ningun proxy intermedio, podemos incluir las siguientes directivas.

/* Establecemos que las paginas no pueden ser cacheadas */
header("Expires: Tue, 01 Jul 2001 06:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

 

En este punto, en el que la sesión del usuario ha sido inicializada en el servidor, y que la información de la sesión ha sido transmitida al usuario a través de una cookie, debemos definir en algun lado de nuestra aplicación una funcion que se encargue de destruir la sesión del usuario. Esta función deberá ser llamada desde varios sitios, siendo el fundamental la página logout.php de nuestra aplicación ( o el método utilizado para desconectar al usuario), así como la página de login.php, ya que consideraremos que cualquier usuario que acceda a esta página desea iniciar sesión en el software, y debemos invalidar sus credenciales anteriores.

function logOut() {
session_unset();
session_destroy();
session_start();
session_regenerate_id(true);
}

 

Para destruir una sesión en php debemos borrar todas las variables del array global $_SESSION mediante una llamada a session_unset(). La llamada a session_destroy() eliminará toda la información asociada con la sesión en el servidor.Trás inutilizar la sesion anterior, vamos a crear una nueva sesión con un identificador nuevo con session_regenerate_id(). Estos pasos nos garantizarán que la sesión anterior ha quedado completamente invalidada.

Un ataque de session fixation es aquel en el que un usuario es capaz de robar la sesión de otro usuario y suplantar su identidad. Para protegernos de dichos ataques un primer enfoque que debemos realizar nada mas inicializar la sesión del usuario es guardar ciertas variables de sesión con información del cliente:

$_SESSION
['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
$_SESSION['SKey'] = uniqid(mt_rand(), true);
$_SESSION['IPaddress'] = ExtractUserIpAddress();
$_SESSION['LastActivity'] = $_SERVER['REQUEST_TIME'];
 

En nuestro caso, los dos campos más importantes son la IP del usuario que realiza la petición HTTP, y la versión de su navegador. Por temas de control de actividad también guardaremos la fecha en la que se realiza la petición al servidor web.

Para protegernos de dichos ataques lo que debemos comprobar en cada petición es que no existan modificaciones en los parámetros del navegador (IP, navegador) , ya que esto significaría que alguien desde una ubicación distinta a la anterior del usuario está intentando hacerse pasar por él. La fecha de la ultima actividad no debe superar un umbral definido por nosotros, como por ejemplo 120 minutos. En caso de que suceda un cambio en alguno de los mencionados parámetros, o que la sesión del usuario haya caducado en el acceso al servidor web, debemos llamar inmediatamente al método logOut() y salir con un exit();

El acceso desde dispositivos móviles puede trastocar los planes de un control exhaustivo de la dirección IP. Un planteamiento alternativo puede ser ignorar el cambio de ip si se ha producido desde un dispositivo móvil, identificable por el User Agent del navegador. En el futuro hablaremos de un control adicional basado en geolocalización y de reglas heurísticas adicionales para determinar si el usuario que se encuentra al otro lado de la conexión es realmente quien se suponía que era al principio.

Ya nos hemos quitado un gran número de problemas para evitar molestos ataques contra la sesión del usuario así que vamos con una última recomendación adicional para proteger una aplicación web frente a ataques de usuarios no autenticados. .

Imaginemos que nuestra pagina web tiene varias paginas que deben ser accedidas de forma anónima, como por ejemplo login.php , register.php y logout.php, y que trás autenticarse al usuario se establece una variable de sesión $_SESSION[‘registered’] = 1 y empieza a acceder a una serie de recursos protegidos;

Al final de nuestro script security.php podemos comprobar la información de la sesión, de modo que si el usuario no está registrado en la aplicación ( $_SESSION['registered'] ) y la página accedida no es ninguna de las mencionadas en el punto anterior, se debe realizar una llamada a exit(). De este modo, un usuario no autenticado no podrá ejecutar ningún script del sistema.

Y os preguntareis, ¿para que vale $_SESSION['SKey']? Pues lo veremos el próximo día.

By | 2016-12-02T10:30:46+00:00 16 Feb. 2015|6 Comments

6 Comments

  1. Alan 3 Junio, 2015 at 1:12 am - Reply

    Muy buen artículo… gracias por compartir esos conocimientos de seguridad.

  2. Sebastian 15 Julio, 2015 at 8:34 pm - Reply

    Hola, Una pregunta: Y lo del SKey? cual es la idea de esa variable aleatoria de session?

  3. Sebastian 16 Julio, 2015 at 12:20 am - Reply

    Hola, una consulta, Para que sería lo de $_SESSION[‘SKey’] ??

  4. Zarith 23 Diciembre, 2015 at 2:14 pm - Reply

    Me quede esperando lo de $_SESSION[‘SKey’] :/

  5. Administrador 6 Diciembre, 2016 at 8:19 pm - Reply

    La idea de generar una clave única y aleatoria en el inicio de sesión (skey) es poder utilizarla como una variable de uso obligado en todos los formularios y operaciones de Aata, baja o modificación de información en vuestra aplicación.
    De este modo, ante la recepción de una petición GET o POST que invoque alguna operación sensible deberéis comprobar si ($_GET[‘SKey’] ==
    $_SESSION[‘SKey’]) . Si no lo es, por seguridad cerramos la sesión.
    De este modo, evitamos que un enlace externo pueda invocar una funcionalidad en nuestra plataforma web, como por ejemplo: http://bank.com/transferencia?cantidad=1000&destino=numerodecuenta
    Si disponemos de una variable como skey y comprobamos su validez, evitaremos este tipo de ataques y mejoraremos la seguridad de la aplicación PHP.

    Esta variable es denominada Token de CSRF. Si tenéis curiosidad podéis consultar la información aquí: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)

  6. sarah 2 Abril, 2017 at 2:32 pm - Reply

    Hola, por casualidad tienes un pequeño ejemplo donde pongas en funcionamiento este tipo de seguridad.
    podrías facilitarme algo.

    Gracias, te felicito por este artículo.

Deja un comentario