10. Manejo de Sesiones y Cookies
Introducción
Section titled “Introducción”En aplicaciones web, mantener el estado entre diferentes peticiones HTTP es un desafío debido a la naturaleza sin estado del protocolo HTTP. PHP ofrece dos mecanismos principales para resolver este problema: sesiones y cookies. Estos mecanismos permiten almacenar información del usuario entre diferentes páginas y visitas al sitio web.
10.1 Sesiones en PHP
Section titled “10.1 Sesiones en PHP”10.1.1 ¿Qué son las sesiones?
Section titled “10.1.1 ¿Qué son las sesiones?”Las sesiones permiten almacenar datos del usuario en el servidor durante un período de tiempo limitado. Cada usuario recibe un identificador único de sesión (generalmente almacenado en una cookie) que se utiliza para acceder a sus datos de sesión almacenados en el servidor.
10.1.2 Variables superglobales: $_SESSION
Section titled “10.1.2 Variables superglobales: $_SESSION”PHP proporciona la variable superglobal $_SESSION para acceder y manipular los datos de sesión. Esta variable es un array asociativo que contiene todas las variables de sesión disponibles para el script actual.
10.1.3 Iniciar una sesión
Section titled “10.1.3 Iniciar una sesión”Antes de poder utilizar variables de sesión, debes iniciar la sesión con la función session_start(). Esta función debe ser llamada antes de cualquier salida al navegador.
<?php// Iniciar sesión (debe ser lo primero antes de cualquier salida HTML)session_start();
// Ahora podemos trabajar con la variable $_SESSION$_SESSION['usuario'] = 'juan_perez';$_SESSION['nivel_acceso'] = 'administrador';$_SESSION['ultimo_acceso'] = time();?>
<!DOCTYPE html><html><head> <title>Ejemplo de Sesión</title></head><body> <h1>Sesión iniciada</h1> <p>Bienvenido, <?php echo $_SESSION['usuario']; ?>!</p></body></html>10.1.4 Comprobar si una sesión está activa
Section titled “10.1.4 Comprobar si una sesión está activa”Puedes verificar si una sesión ya está iniciada utilizando la función session_status():
<?phpif (session_status() === PHP_SESSION_NONE) { session_start();}
// Ahora es seguro trabajar con $_SESSION?>O comprobar si existe una variable específica en la sesión:
<?phpsession_start();
// Comprobar si el usuario ha iniciado sesiónif (isset($_SESSION['usuario'])) { echo "Bienvenido de nuevo, " . $_SESSION['usuario'];} else { echo "Por favor, inicia sesión";}?>10.1.5 Eliminar datos de sesión
Section titled “10.1.5 Eliminar datos de sesión”Puedes eliminar variables específicas de la sesión o destruir completamente la sesión:
<?phpsession_start();
// Eliminar una variable específica de la sesiónunset($_SESSION['ultimo_acceso']);
// Eliminar todas las variables de sesión pero mantener la sesión activa$_SESSION = array();
// Destruir completamente la sesiónsession_destroy();?>10.1.6 Implementación de inicio y cierre de sesión
Section titled “10.1.6 Implementación de inicio y cierre de sesión”A continuación se muestra un ejemplo completo de implementación de inicio y cierre de sesión:
<?phpsession_start();
// Verificar si el usuario ya ha iniciado sesiónif (isset($_SESSION['usuario_id'])) { // Redirigir a la página principal si ya está autenticado header("Location: dashboard.php"); exit;}
$error = "";
// Procesar el formulario cuando se envíaif ($_SERVER["REQUEST_METHOD"] == "POST") { // En un caso real, estos valores vendrían de una base de datos $usuario_correcto = "admin"; $password_correcto = "password123";
// Obtener datos del formulario $usuario = $_POST['usuario'] ?? ''; $password = $_POST['password'] ?? '';
// Validar credenciales if ($usuario === $usuario_correcto && $password === $password_correcto) { // Credenciales correctas, iniciar sesión $_SESSION['usuario_id'] = 1; $_SESSION['usuario_nombre'] = $usuario; $_SESSION['tiempo_inicio'] = time();
// Recordar usuario si se seleccionó la casilla if (isset($_POST['recordar']) && $_POST['recordar'] == 1) { // Crear cookie que dura 30 días setcookie('usuario_recordado', $usuario, time() + (86400 * 30), "/"); }
// Redirigir al panel de control header("Location: dashboard.php"); exit; } else { $error = "Usuario o contraseña incorrectos"; }}?>
<!DOCTYPE html><html><head> <title>Iniciar Sesión</title> <style> body { font-family: Arial, sans-serif; max-width: 400px; margin: 0 auto; padding: 20px; } .error { color: red; margin-bottom: 15px; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; } input[type="text"], input[type="password"] { width: 100%; padding: 8px; } button { padding: 10px 15px; background-color: #4CAF50; color: white; border: none; cursor: pointer; } </style></head><body> <h1>Iniciar Sesión</h1>
<?php if ($error): ?> <div class="error"><?php echo $error; ?></div> <?php endif; ?>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>"> <div class="form-group"> <label for="usuario">Usuario:</label> <input type="text" id="usuario" name="usuario" value="<?php echo isset($_COOKIE['usuario_recordado']) ? $_COOKIE['usuario_recordado'] : ''; ?>" required> </div>
<div class="form-group"> <label for="password">Contraseña:</label> <input type="password" id="password" name="password" required> </div>
<div class="form-group"> <label> <input type="checkbox" name="recordar" value="1" <?php echo isset($_COOKIE['usuario_recordado']) ? 'checked' : ''; ?>> Recordar usuario </label> </div>
<button type="submit">Iniciar Sesión</button> </form></body></html><?phpsession_start();
// Verificar si el usuario ha iniciado sesiónif (!isset($_SESSION['usuario_id'])) { // Redirigir al login si no está autenticado header("Location: login.php"); exit;}
// Verificar tiempo de inactividad (15 minutos = 900 segundos)$tiempo_inactividad = 900;if (isset($_SESSION['tiempo_inicio']) && (time() - $_SESSION['tiempo_inicio'] > $tiempo_inactividad)) { // La sesión ha expirado por inactividad session_unset(); // Eliminar todas las variables de sesión session_destroy(); // Destruir la sesión
header("Location: login.php?expirado=1"); exit;}
// Actualizar el tiempo de inicio para reiniciar el contador de inactividad$_SESSION['tiempo_inicio'] = time();?>
<!DOCTYPE html><html><head> <title>Panel de Control</title> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; } .header { display: flex; justify-content: space-between; align-items: center; } .logout { background-color: #f44336; color: white; padding: 8px 15px; text-decoration: none; } </style></head><body> <div class="header"> <h1>Panel de Control</h1> <a href="logout.php" class="logout">Cerrar Sesión</a> </div>
<p>Bienvenido, <?php echo htmlspecialchars($_SESSION['usuario_nombre']); ?>!</p>
<p>Esta es una página protegida que solo pueden ver los usuarios autenticados.</p>
<p>Información de la sesión:</p> <ul> <li>ID de usuario: <?php echo $_SESSION['usuario_id']; ?></li> <li>Tiempo de inicio: <?php echo date('Y-m-d H:i:s', $_SESSION['tiempo_inicio']); ?></li> </ul></body></html><?phpsession_start();
// Eliminar todas las variables de sesión$_SESSION = array();
// Si se está usando una cookie de sesión, eliminarla tambiénif (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );}
// Finalmente, destruir la sesiónsession_destroy();
// Redirigir al loginheader("Location: login.php?logout=1");exit;?>10.1.7 Configuración de sesiones
Section titled “10.1.7 Configuración de sesiones”PHP ofrece varias opciones para configurar el comportamiento de las sesiones:
<?php// Configurar opciones de sesión antes de iniciarlaini_set('session.gc_maxlifetime', 3600); // Duración de la sesión en segundos (1 hora)ini_set('session.cookie_lifetime', 3600); // Duración de la cookie de sesiónini_set('session.use_strict_mode', 1); // Modo estricto para mayor seguridadini_set('session.cookie_httponly', 1); // Evita acceso a la cookie desde JavaScriptini_set('session.cookie_secure', 1); // Solo enviar cookie por HTTPSini_set('session.cookie_samesite', 'Lax'); // Protección contra CSRF
// Iniciar la sesión con las configuraciones aplicadassession_start();?>También puedes configurar estas opciones en el archivo php.ini o usando session_set_cookie_params() antes de session_start().
10.2 Cookies en PHP
Section titled “10.2 Cookies en PHP”10.2.1 ¿Qué son las cookies?
Section titled “10.2.1 ¿Qué son las cookies?”Las cookies son pequeños archivos de texto que se almacenan en el navegador del usuario. A diferencia de las sesiones, las cookies se guardan en el lado del cliente (navegador) y no en el servidor.
10.2.2 Variables superglobales: $_COOKIE
Section titled “10.2.2 Variables superglobales: $_COOKIE”PHP proporciona la variable superglobal $_COOKIE para acceder a las cookies enviadas por el navegador del usuario. Esta variable es un array asociativo que contiene todas las cookies disponibles para el script actual.
10.2.3 Crear cookies
Section titled “10.2.3 Crear cookies”Para crear una cookie, se utiliza la función setcookie():
<?php// Sintaxis básica: setcookie(nombre, valor, tiempo_expiracion, ruta, dominio, seguro, httponly)
// Crear una cookie que expira en 30 díassetcookie('usuario', 'juan_perez', time() + (86400 * 30), "/");
// Crear una cookie que expira al cerrar el navegador (cookie de sesión)setcookie('preferencia_tema', 'oscuro', 0, "/");
// Crear una cookie segura (solo se envía por HTTPS)setcookie('token', 'abc123', time() + 3600, "/", "", true, true);?>10.2.4 Leer cookies
Section titled “10.2.4 Leer cookies”Para leer el valor de una cookie, simplemente accede a la variable superglobal $_COOKIE:
<?php// Verificar si existe una cookieif (isset($_COOKIE['usuario'])) { echo "Bienvenido de nuevo, " . htmlspecialchars($_COOKIE['usuario']);} else { echo "Bienvenido, visitante";}
// Acceder a una cookie con un valor predeterminado si no existe$tema = $_COOKIE['preferencia_tema'] ?? 'claro';echo "Tema actual: $tema";?>10.2.5 Modificar cookies
Section titled “10.2.5 Modificar cookies”Para modificar una cookie existente, simplemente crea una nueva cookie con el mismo nombre:
<?php// Modificar una cookie existentesetcookie('preferencia_tema', 'claro', time() + (86400 * 30), "/");?>10.2.6 Eliminar cookies
Section titled “10.2.6 Eliminar cookies”Para eliminar una cookie, establece su tiempo de expiración en el pasado:
<?php// Eliminar una cookiesetcookie('usuario', '', time() - 3600, "/");?>10.2.7 Implementación de “Recordar usuario”
Section titled “10.2.7 Implementación de “Recordar usuario””A continuación se muestra un ejemplo de cómo implementar la funcionalidad “Recordar usuario” utilizando cookies:
<?phpsession_start();
// Verificar si hay una cookie de "recordar usuario"if (!isset($_SESSION['usuario_id']) && isset($_COOKIE['auth_token'])) { // En un caso real, verificaríamos este token en la base de datos $token = $_COOKIE['auth_token']; $usuario_id = verificarToken($token); // Función hipotética
if ($usuario_id) { // Token válido, iniciar sesión automáticamente $_SESSION['usuario_id'] = $usuario_id; $_SESSION['usuario_nombre'] = obtenerNombreUsuario($usuario_id); // Función hipotética $_SESSION['tiempo_inicio'] = time(); }}
// Función para crear un token de autenticaciónfunction crearTokenRecordar($usuario_id) { // En un caso real, generaríamos un token único y lo almacenaríamos en la base de datos $token = bin2hex(random_bytes(32)); // Genera un token aleatorio seguro
// Almacenar el token en una cookie que dura 30 días setcookie('auth_token', $token, time() + (86400 * 30), "/", "", true, true);
// Guardar el token en la base de datos junto con el ID de usuario // guardarTokenEnBaseDeDatos($usuario_id, $token); // Función hipotética
return $token;}
// Función para eliminar el token de "recordar usuario"function eliminarTokenRecordar() { if (isset($_COOKIE['auth_token'])) { // Eliminar el token de la base de datos // eliminarTokenDeBaseDeDatos($_COOKIE['auth_token']); // Función hipotética
// Eliminar la cookie setcookie('auth_token', '', time() - 3600, "/"); }}?>10.2.8 Seguridad en cookies
Section titled “10.2.8 Seguridad en cookies”Las cookies pueden ser vulnerables a varios tipos de ataques. Aquí hay algunas prácticas recomendadas para mejorar la seguridad:
| Parámetro | Descripción | Recomendación |
|---|---|---|
| httponly | Evita que la cookie sea accesible mediante JavaScript | Establecer a true para cookies sensibles |
| secure | La cookie solo se envía a través de conexiones HTTPS | Establecer a true en sitios con HTTPS |
| samesite | Controla cuándo se envían las cookies en solicitudes entre sitios | Usar ‘Strict’ o ‘Lax’ para prevenir CSRF |
| path | Ruta en el servidor donde la cookie estará disponible | Limitar al mínimo necesario, no usar ’/’ si no es necesario |
| domain | Dominio para el que la cookie es válida | Especificar solo si es necesario compartir entre subdominios |
<?php// Ejemplo de cookie segurasetcookie( 'token_seguro', // Nombre 'valor_encriptado_aqui', // Valor (idealmente encriptado) time() + 3600, // Expiración (1 hora) '/app/', // Ruta (restringida a /app/) 'ejemplo.com', // Dominio true, // Secure (solo HTTPS) true // HttpOnly (inaccesible por JavaScript));
// Para PHP 7.3+ puedes usar el parámetro adicional para samesite$opciones = [ 'expires' => time() + 3600, 'path' => '/app/', 'domain' => 'ejemplo.com', 'secure' => true, 'httponly' => true, 'samesite' => 'Strict' // 'None', 'Lax', o 'Strict'];
setcookie('token_seguro', 'valor_encriptado_aqui', $opciones);?>10.3 Comparación entre Sesiones y Cookies
Section titled “10.3 Comparación entre Sesiones y Cookies”| Característica | Sesiones | Cookies |
|---|---|---|
| Almacenamiento | Servidor | Cliente (navegador) |
| Seguridad | Mayor (datos sensibles en servidor) | Menor (datos expuestos al cliente) |
| Capacidad | Limitada por configuración del servidor | Limitada (~4KB por cookie) |
| Duración | Temporal (hasta cierre de navegador o timeout) | Configurable (temporal o persistente) |
| Dependencia | Requiere cookie o URL para ID de sesión | No requiere soporte adicional |
| Uso típico | Datos de autenticación, carritos de compra | Preferencias, seguimiento, recordar usuario |
10.4 Mejores prácticas
Section titled “10.4 Mejores prácticas”10.4.1 Seguridad en sesiones
Section titled “10.4.1 Seguridad en sesiones”- Regenerar ID de sesión: Regenera el ID de sesión después de eventos importantes como inicio de sesión o cambio de privilegios.
<?phpsession_start();
// Después de una autenticación exitosaif ($autenticacion_exitosa) { // Regenerar ID de sesión para prevenir ataques de fijación de sesión session_regenerate_id(true);
$_SESSION['usuario_id'] = $usuario_id; // Otros datos de sesión...}?>-
Validar datos de sesión: Siempre valida los datos almacenados en la sesión antes de usarlos.
-
Establecer tiempo de expiración: Implementa un mecanismo de timeout para sesiones inactivas.
-
Usar HTTPS: Configura las cookies de sesión para que solo se transmitan por HTTPS.
10.4.2 Gestión de datos sensibles
Section titled “10.4.2 Gestión de datos sensibles”-
No almacenar datos sensibles en cookies: Las cookies son visibles para el usuario y pueden ser manipuladas.
-
Encriptar datos sensibles: Si necesitas almacenar datos sensibles, encriptalos antes.
<?php// Encriptar datos antes de almacenarlos en una cookie$datos_sensibles = "información_confidencial";$clave_encriptacion = "clave_secreta_muy_larga_y_compleja"; // En producción, usar una clave segura
// Método simple (para datos no críticos)$datos_encriptados = base64_encode(openssl_encrypt( $datos_sensibles, 'AES-256-CBC', $clave_encriptacion, 0, substr(md5($clave_encriptacion), 0, 16)));
setcookie('datos', $datos_encriptados, time() + 3600, "/", "", true, true);
// Para desencriptarif (isset($_COOKIE['datos'])) { $datos_desencriptados = openssl_decrypt( base64_decode($_COOKIE['datos']), 'AES-256-CBC', $clave_encriptacion, 0, substr(md5($clave_encriptacion), 0, 16) );
echo "Datos desencriptados: $datos_desencriptados";}?>10.4.3 Manejo de errores y excepciones
Section titled “10.4.3 Manejo de errores y excepciones”Implementa un manejo adecuado de errores para situaciones como sesiones expiradas o cookies bloqueadas:
<?php// Verificar si las cookies están habilitadassetcookie('test_cookie', '1', 0, '/');
if (isset($_COOKIE['test_cookie'])) { echo "Las cookies están habilitadas";} else { echo "Las cookies están deshabilitadas. Esta aplicación requiere cookies para funcionar correctamente.";}
// Manejar sesión expiradasession_start();
if (isset($_SESSION['tiempo_ultimo_acceso'])) { $inactividad = 1800; // 30 minutos
if (time() - $_SESSION['tiempo_ultimo_acceso'] > $inactividad) { // La sesión ha expirado session_unset(); session_destroy();
// Redirigir con mensaje header("Location: login.php?expirado=1"); exit; }}
// Actualizar tiempo de último acceso$_SESSION['tiempo_ultimo_acceso'] = time();?>Conclusión
Section titled “Conclusión”El manejo adecuado de sesiones y cookies es fundamental para desarrollar aplicaciones web seguras y con buena experiencia de usuario. Las sesiones son ideales para almacenar datos sensibles y de autenticación en el servidor, mientras que las cookies son útiles para almacenar preferencias de usuario y facilitar funcionalidades como “recordarme” entre visitas.
Al implementar estos mecanismos, siempre prioriza la seguridad siguiendo las mejores prácticas y considerando las implicaciones de privacidad para los usuarios de tu aplicación.