En esta entrega se describe cómo aplicar las medidas de seguridad vistas en los artículos anteriores en aplicaciones web PHP. VI de VII.
Gestión de sesiones web I: introducción
Gestión de sesiones web II: ejemplos y clasificación de ataques
Gestión de sesiones web III: ataques de predicción de sesión y XSS
Gestión de sesiones web IV: ataques de fijación de sesión y eavesdropping
Gestión de sesiones web V: errores en el cierre de sesión
Descripción del funcionamiento
PHP almacena los datos de cada sesión en un fichero individual bajo el directorio definido por la variable session.save_path. El nombre de este archivo incluye el identificador de sesión y el formato en el que almacena la información es muy sencillo:
favcolor|s:5:"green";animal|s:3:"cat";time|i:1328180510;
El mecanismo mediante el cual se pueden almacenar y leer datos de sesión es a través del array $_SESSION, para ello el servidor realiza las siguientes acciones al recibir una petición perteneciente a una sesión:
-
Lee el identificador de sesión (generalmente de una cookie).
-
Busca un archivo en el directorio session.save_path cuyo nombre contiene el identificador.
-
Procesa este archivo y guarda en el array $_SESSION las variables que contiene.
-
Añade la cookie de sesión a la respuesta.
-
Procesa el resto de la página PHP que contiene la lógica de la aplicación.
-
"Serializa" el contenido de $_SESSION y lo almacena en el archivo de sesión para su recuperación posterior.
Además, elimina los archivos si no han sido modificados (cada vez que se procesa una petición se modifica su archivo de sesión) en un tiempo definido por la variable session.gc_maxlifetime. La ejecución de este proceso de eliminación puede iniciarse de forma aleatoria, con una probabilidad de ejecución definida por session.gc_probability y session.gc_divisor, o, en algunas distribuciones, a través de una tarea del cron:
09,39 * * * * root [ -x /usr/lib/php5/maxlifetime ]
&& [ -d /var/lib/php5 ]
&& find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1
-type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete
Este mecanismo de almacenamiento de información de sesión tiene inconvenientes como la serialización de peticiones concurrentes pero, por otro lado, se pueden especificar mecanismos de almacenamiento de sesión alternativos como, por ejemplo, en memoria o en base de datos mediante session.save_handler, e incluso desarrollados "ad hoc" a través de la función session_set_save_handler.
Configuración segura
No todas las medidas descritas a continuación son necesarias, se debe evaluar el perfil de riesgo de la aplicación para implantar unas medidas acorde con él.
Medidas contra la predicción de sesión
-
Aleatorización y longitud suficiente del identificador de sesión: la configuración por defecto de aleatorización del identificador de sesión es suficientemente buena, pero se pueden añadir fuentes de datos para la generación del identificador mediante session.entropy_file y session.entropy_length para, por ejemplo, utilizar el API de Windows o el archivo /dev/random en sistemas Unix.
Medidas contra la captura del identificador a través de ataques XSS
-
Las cookies sólo han de ser accesibles a través del protocolo HTTP: activar la opción session.cookie_httponly que se encuentra desactivada por defecto.
-
Deshabilitar el método TRACE: configurable en el servidor HTTP.
Medidas contra la fijación de sesión
-
Renovar el identificador al autenticarse el usuario o asignarlo únicamente después de la autenticación: utilizar la función session_regenerate_id, siempre con el parámetro "$delete_old_session = true" para que el identificador de la sesión anterior no sea utilizable.
-
Permitir únicamente el identificador en cookies: esta restricción, activa por defecto, se controla mediante la variable session.use_only_cookies.
-
Asociar el identificador a información del usuario única como su dirección IP: la dirección IP ,que se puede obtener de la variable $_SERVER['REMOTE_ADDR'], puede almacenarse en los datos de sesión, a través de $_SESSION, y simplemente en cada nueva petición comprobar que no ha cambiado. Esta medida no tiene por qué limitarse a la dirección IP, se puede establecer un perfil más detallado a traves de acciones comunes, patrones de navegación, localización, etc.
Medidas contra el eavesdropping
-
Utilizar el protocolo HTTPS: configurable en el servidor HTTP.
-
Utilizar la opción "secure" en las cookies de sesión: activar la opción session.cookie_secure.
Medidas contra los errores en el cierre de sesión
-
Establecer un timeout de sesión: se puede utilizar un código similar al siguiente para controlar este timeout
if (!isset($_SESSION['timeout_idle'])) {
$_SESSION['timeout_idle'] = time() + ini_get('session.gc_maxlifetime');
} else {
if ($_SESSION['timeout_idle'] < time()) {
//destroy session
} else {
$_SESSION['timeout_idle'] = time() + ini_get('session.gc_maxlifetime');
}
}
Se puede delegar esta medida de seguridad en el mecanismo de eliminación de archivos de sesión que no han sido accedidos en el tiempo definido por session.gc_maxlifetime, pero entonces habrá que ajustar su ejecución para que no sea aleatoria y para que dependa de una tarea programada.
-
Establecer un tiempo máximo de validez de sesión: este timeout puede ser establecido mediante un código similar al anterior, utilizando el parámetro session.cookie_lifetime, etc.
-
Utilizar cookies no persistentes: el tiempo de validez de la cookie se controla mediante el parámetro session.cookie_lifetime que por defecto es 0, lo que significa que no es persistente. Por otro lado, por defecto las cookies están restringidas al dominio y directorio raiz del servidor web (opciones controladas mediante session.cookie_domain y session.cookie_path).
-
Invalidar y no reutilizar los identificadores de sesión: cuando se destruye la sesión, mediante session.destroy, se elimina el archivo de sesión, por lo que cuando el usuario acceda de nuevo el servidor web no reconocerá la sesión. Otra cosa a tener en cuenta es invocar session_regenerate_id siempre incluyendo el parámetro "$delete_old_session = true" para inutilizar el identificador anterior.
Medidas ante aspectos propios de la implementación de la gestión de sesiones de PHP
-
Restringir el acceso al directorio session.save_path donde se guardan los archivos de sesión sin encriptar. En la instalación por defecto, sólo tiene acceso a ese directorio el usuario bajo el que se ejecuta el servidor web. Los usuarios no deben ni poder listar los archivos ya que su nombre contiene el identificador de sesión.
En la séptima y ultima entrega se describirá la implantación de estos mecanimos de seguridad en otros frameworks de programación web.