Las sesiones en PHP permiten conservar información del usuario entre peticiones HTTP, que por naturaleza son sin estado. Un identificador de sesión almacenado en una cookie conecta al usuario con sus datos guardados en el servidor. Manejar sesiones de forma correcta requiere entender cómo crearlas, destruirlas y protegerlas frente a ataques comunes como el session fixation o el robo de cookie.
session_start() y $_SESSION
Toda página que necesite acceder a datos de sesión debe llamar a session_start() antes de enviar cualquier salida. A partir de ese momento, $_SESSION es un array asociativo donde se puede leer y escribir información que persiste entre peticiones.
<?php
session_start();
// Guardar datos en la sesión
$_SESSION['usuario_id'] = 42;
$_SESSION['nombre'] = 'Ana García';
$_SESSION['roles'] = ['editor', 'lector'];
// Leer datos en otra petición (misma sesión)
if (isset($_SESSION['usuario_id'])) {
echo 'Bienvenida, ' . htmlspecialchars($_SESSION['nombre'], ENT_QUOTES, 'UTF-8');
}
// Eliminar una clave concreta
unset($_SESSION['roles']);
// Comprobar si hay sesión activa
echo session_id(); // devuelve el ID actual
echo session_status(); // PHP_SESSION_ACTIVE si está iniciada
?>
Login seguro con session_regenerate_id()
El ataque de session fixation consiste en que el atacante fuerza al usuario a usar un ID de sesión conocido de antemano. La defensa es regenerar el ID de sesión justo después de que el usuario se autentique correctamente.
<?php
session_start();
function iniciarSesionUsuario(int $idUsuario, string $nombre): void
{
// Regenerar el ID ANTES de guardar datos del usuario
session_regenerate_id(true); // true = destruye la sesión anterior
$_SESSION['usuario_id'] = $idUsuario;
$_SESSION['nombre'] = $nombre;
$_SESSION['login_time'] = time();
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? '';
}
// Ejemplo de uso tras verificar credenciales en la BD
if (autenticarCredenciales($_POST['email'], $_POST['password'])) {
$usuario = obtenerUsuarioPorEmail($_POST['email']);
iniciarSesionUsuario($usuario['id'], $usuario['nombre']);
header('Location: /panel');
exit;
}
?>
Caducidad manual de sesión con timestamps
PHP no ofrece un mecanismo nativo de caducidad de sesión por inactividad, pero es fácil implementarlo guardando el timestamp de la última actividad y comprobándolo en cada petición.
<?php
session_start();
const TIEMPO_INACTIVIDAD = 1800; // 30 minutos en segundos
function verificarSesionActiva(): bool
{
if (!isset($_SESSION['usuario_id'])) {
return false;
}
$ultimaActividad = $_SESSION['ultima_actividad'] ?? 0;
if ((time() - $ultimaActividad) > TIEMPO_INACTIVIDAD) {
// Sesión caducada: destruirla completamente
$_SESSION = [];
session_destroy();
return false;
}
// Actualizar el timestamp de actividad
$_SESSION['ultima_actividad'] = time();
return true;
}
if (!verificarSesionActiva()) {
header('Location: /login?motivo=sesion_caducada');
exit;
}
?>
session_destroy() y cerrar sesión limpiamente
Para cerrar la sesión de forma completa hay que vaciar el array $_SESSION, invalidar la cookie y llamar a session_destroy(). Omitir alguno de estos pasos puede dejar restos de datos accesibles.
<?php
session_start();
function cerrarSesion(): void
{
// 1. Vaciar todos los datos de sesión
$_SESSION = [];
// 2. Eliminar la cookie de sesión del navegador
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
// 3. Destruir la sesión en el servidor
session_destroy();
}
cerrarSesion();
header('Location: /login');
exit;
?>
Configuración segura en php.ini
<?php
// Configurar la sesión por código si no se puede tocar php.ini
ini_set('session.cookie_httponly', '1'); // JS no puede leer la cookie
ini_set('session.cookie_secure', '1'); // solo HTTPS
ini_set('session.cookie_samesite', 'Lax'); // protección CSRF básica
ini_set('session.use_only_cookies', '1'); // sin IDs en URL
ini_set('session.gc_maxlifetime', '1800'); // 30 min de vida máxima
session_start();
?>
La documentación oficial del módulo de sesiones de PHP incluye la lista completa de directivas de php.ini, opciones de almacenamiento personalizado con session_set_save_handler() y guías sobre cómo proteger las sesiones en entornos de producción.
