2.2 · Sesiones, cookies y autenticación simple

Nivel 2 · PHP y la Web

2.2Sesiones, cookies y autenticación simple

Objetivo: Conservar un estado entre páginas (sesiones del lado del servidor, cookies) y construir una autenticación simple pero SEGURA (contraseñas con hash, sesión protegida) — la base de las cuentas de usuario.
Tiempo estimado: 11 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • HTTP lo olvida todo: cada petición es independiente — cookies y sesiones añaden la «memoria» entre páginas (quién está conectado, cesta, preferencias).
  • Sesiones para lo sensible, cookies para las preferencias: datos de confianza del lado del SERVIDOR ($_SESSION, no modificables) — nunca un dato sensible en una cookie modificable.
  • Contraseñas con hash, nunca en claro: password_hash en la inscripción, password_verify en la conexión, ID de sesión regenerado — sin ninguna excepción.

Minicaso hilado — Riad mantiene conectados a sus miembros

Riad continúa con su formulario (2.1): los miembros de la asociación deben seguir conectados de una página a otra para ver su espacio personal. Como HTTP no tiene estado, añade una memoria: una cookie para la preferencia de idioma (no sensible), una sesión para la identidad (sensible, lado del servidor). Al conectarse comprueba la contraseña con password_verify sobre un hash, regenera el ID de sesión, guarda el identificador en $_SESSION; cada página protegida comprueba la sesión. En 2.3, factorizará la comprobación en un archivo incluido en todas partes; en 2.4, fechará la última conexión.

Continuación del hilo 2.1: el formulario de Riad se convierte en un espacio de miembros con memoria — y continúa en 2.3 y 2.4.

1. Dar una memoria a HTTP: cookies y sesiones

El protocolo HTTP es sin estado (stateless): cada petición es INDEPENDIENTE, el servidor no «recuerda» nada entre dos páginas. Para memorizar un estado (quién está conectado, una cesta, preferencias), dos mecanismos. Las cookies: pequeños datos guardados en el NAVEGADOR, reenviados al servidor en cada petición — creadas con setcookie(), leídas en $_COOKIE. Lado del cliente, por tanto VISIBLES y MODIFICABLES por el usuario: reservadas a datos no sensibles (idioma, tema), con opciones de seguridad (HttpOnly contra el robo por XSS, Secure solo para HTTPS, SameSite contra el CSRF). Las sesiones: el estado se guarda del lado del SERVIDOR (el usuario no puede modificarlo), el navegador solo conserva un identificador de sesión. En PHP: session_start() al principio del script (antes de cualquier salida), luego almacenamiento y lectura vía $_SESSION ($_SESSION['user_id'] = 42;). Los datos sensibles viven en sesión — nunca en claro en una cookie. Riad lo aplica: idioma en cookie, identidad en sesión.

2. Una autenticación simple pero segura

Las sesiones sirven en particular a la autenticación. El ciclo: al CONECTARSE, se comprueban el identificador y la contraseña, luego se guarda la identidad en sesión ($_SESSION['user_id']); en cada página PROTEGIDA, se comprueba la sesión (si no, redirección a la conexión); al DESCONECTARSE, se destruye la sesión (session_destroy()). Tres protecciones no son negociables. Primero, las contraseñas se guardan con HASH con password_hash() y se comprueban con password_verify() — nunca en claro, nunca con un hash débil: una fuga de la base expondría si no todas las cuentas. Después, se regenera el identificador al conectarse (session_regenerate_id()) contra la fijación de sesión, con cookies de sesión seguras y HTTPS. Por último, se controlan los ACCESOS: comprobar no solo que el usuario está conectado (autenticación), sino que TIENE DERECHO a acceder al recurso (autorización) — si no, un miembro lee los datos de otro cambiando un id en la URL.

3. Las trampas que comprometen cuentas

La autenticación es un ámbito de alto riesgo: un error compromete cuentas reales. Trampas a desterrar: guardar una contraseña en claro; olvidar regenerar el ID de sesión; dejar las cookies de sesión sin HttpOnly/Secure/SameSite; trabajar sin HTTPS; comprobar la conexión pero no la autorización; revelar con mensajes de error demasiado precisos qué correos existen; no limitar los intentos (fuerza bruta); construir las consultas por concatenación en lugar de consultas preparadas (inyección SQL, nivel 3). Riad marcó cada punto antes de abrir el espacio de miembros. Y en un PROYECTO REAL, se privilegian los sistemas de autenticación PROBADOS de los frameworks, que gestionan correctamente estas sutilezas: comprender los mecanismos (como aquí) es esencial, implementarlos con rigor lo es aún más.

Error frecuente de interpretación: «Guardar el identificador en una cookie es lo mismo que una sesión — y más simple». No. Una cookie vive en el navegador: el usuario la ve, la modifica, la falsifica — poner «user_id = 1» o un rol es dejar que cada uno se atribuya la identidad que quiera. La sesión guarda los datos del lado del servidor, fuera de alcance: el navegador solo tiene un identificador opaco. La regla de Riad es tajante: todo lo que genera confianza (identidad, rol, cesta) vive en $_SESSION; la cookie solo lleva preferencias no críticas, protegida por HttpOnly, Secure y SameSite.
Cookies frente a sesiones Cliente frente a servidor CookiesDatos del lado del cliente (modificables) — preferencias+SesionesDatos del lado del servidor (seguros) — identidad, cesta+SeguridadHash, ID regenerado, HTTPS, autorización Sesiones para el estado sensible; cookies para preferencias no críticas.
Cliente frente a servidor
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) HTTP es SIN ESTADO: Riad debe añadir una memoria para mantener conectados a sus miembros. 2) Las COOKIES guardan preferencias del lado del cliente (idioma) — modificables, por tanto nunca un dato sensible, con HttpOnly, Secure, SameSite. 3) Las SESIONES guardan la identidad del lado del servidor vía session_start y luego $_SESSION — el navegador solo guarda un identificador. 4) La SEGURIDAD lo bloquea todo: contraseñas con hash (password_hash/verify), ID regenerado al conectarse, HTTPS y autorización comprobada en cada página. Lección: sensible = servidor, preferencias = cookie.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — La conexión de los miembros de Riad

Sesión + contraseña con hash, como en casa de Riad:

session_start();
if (password_verify($_POST['mdp'] ?? '', $user['hash'])) {
  session_regenerate_id(true);
  $_SESSION['user_id'] = (int) $user['id'];
}
// página protegida :
// if (!isset($_SESSION['user_id'])) { header('Location: connexion.php'); exit; }

Lectura: comprobación sobre el hash, ID regenerado contra la fijación, identidad del lado del servidor.

Lección: comprobar también la autorización (el DERECHO de acceso), no solo la conexión.

Vocabulario de la sección

HTTP sin estado (stateless)
Cada petición HTTP es independiente, el servidor no recuerda las anteriores; cookies y sesiones añaden una memoria entre páginas.

Ejemplo sencillo: Riad debe añadir una memoria para mantener conectados a sus miembros.

Lo que no es: un servidor que reconoce espontáneamente a sus visitantes.

Reflejo: estado entre páginas = cookie o sesión a prever.

Cookies ($_COOKIE)
Pequeños datos guardados en el NAVEGADOR, reenviados en cada petición (setcookie / $_COOKIE); lado del cliente por tanto modificables — opciones HttpOnly, Secure, SameSite.

Ejemplo sencillo: Riad memoriza el idioma elegido en una cookie.

Lo que no es: un almacenamiento seguro para la identidad o un rol.

Reflejo: cookie = solo preferencias no sensibles.

Sesiones ($_SESSION)
Estado guardado DEL LADO DEL SERVIDOR, no modificable por el usuario, el navegador solo guarda un identificador; session_start() y luego $_SESSION — el mecanismo seguro.

Ejemplo sencillo: La identidad de los miembros de Riad vive en $_SESSION['user_id'].

Lo que no es: un dato que el usuario puede editar en su navegador.

Reflejo: dato de confianza = sesión.

Autenticación por sesión
Conexión: comprobar identificador + contraseña y luego guardar la identidad en sesión; páginas protegidas: comprobar la sesión; desconexión: destruir la sesión.

Ejemplo sencillo: Riad protege el espacio de miembros con isset($_SESSION['user_id']).

Lo que no es: una página que confía en una cookie modificable.

Reflejo: cada página sensible = comprobación de sesión.

Seguridad de sesión
Contraseñas con HASH (password_hash/verify, nunca en claro), ID regenerado al conectarse, cookies seguras, HTTPS y control de accesos.

Ejemplo sencillo: Riad aplica hash en la inscripción y comprueba con password_verify.

Lo que no es: una contraseña guardada en claro o en md5.

Reflejo: nueva autenticación = lista de seguridad completa.

En la práctica — En la práctica — Gestionar el estado y una autenticación simple

  1. Inicie una sesión (session_start() al inicio del script, antes de cualquier salida) y guarde/lea datos vía $_SESSION.
  2. Cree una cookie con setcookie() (opciones HttpOnly/Secure) y léala vía $_COOKIE; comprenda que está guardada del lado del cliente (modificable).
  3. Construya una autenticación: al conectarse, compruebe la contraseña (password_verify sobre un hash), guarde $_SESSION['user_id'], regenere el ID de sesión.
  4. Proteja las páginas (comprobar la sesión, redirigir si no) y gestione la desconexión (session_destroy); recuerde: contraseñas con HASH, sesión protegida, HTTPS.
Conserva un estado entre páginas (sesiones del lado del servidor, cookies) y construye una autenticación simple pero SEGURA (contraseñas con hash, sesión protegida) — la base de las cuentas de usuario.

Script listo para decir — justificar la sesión ante el responsable asociativo (30 s)

«Para el espacio de miembros, la identidad vive en sesión, del lado del servidor: el miembro no puede modificarla. La cookie solo lleva el idioma. Las contraseñas tienen hash, nunca en claro, y regenero el identificador en cada conexión. Si alguien falsifica su cookie, no obtiene ningún acceso.»

Para decir mostrando una cookie modificada que no da ningún acceso; la demostración convence.

Modelo copiar-pegar — conexión y página protegida

' . htmlspecialchars('Identifiants invalides.', ENT_QUOTES, 'UTF-8') . '

'; // --- página protegida (espace.php) --- // session_start(); // if (!isset($_SESSION['user_id'])) { header('Location: connexion.php'); exit; } // --- desconexión --- // $_SESSION = []; session_destroy();

Preferencia de idioma

Riad memoriza el francés o el árabe en una cookie de larga duración: no sensible, perfecto para el cliente.

Cesta sensible

El contenido de la cesta de la tienda asociativa vive en sesión: el miembro no puede modificar los precios.

Desconexión limpia

Un clic vacía $_SESSION y destruye la sesión: en un ordenador compartido, ningún sucesor recupera la cuenta.

Hacia el framework

En un proyecto real, Riad confiará la autenticación al sistema probado del framework — mismos principios, sutilezas gestionadas.

Prudencia: No guarde NUNCA una contraseña en claro (ni con un hash débil): una fuga de la base expondría todas las cuentas, con consecuencias graves para personas reales. Use password_hash en la inscripción y password_verify en la conexión, sin excepción. Esta guía plantea los gestos básicos — haga revisar toda autenticación real por un desarrollador experimentado antes de publicarla.

✓ Buenas prácticas

  • Usar las SESIONES para el estado sensible (identidad, cesta).
  • Aplicar hash a las contraseñas con password_hash / password_verify, nunca en claro.
  • Regenerar el ID de sesión al conectarse + cookies seguras + HTTPS.

✗ Errores frecuentes

  • Guardar datos de confianza en una cookie (modificable por el usuario).
  • Guardar una contraseña en claro o con md5/sha1.
  • Comprobar solo la conexión y olvidar la autorización (acceso a datos ajenos).

Puntos clave

  • HTTP es SIN ESTADO (cada petición independiente); COOKIES (lado del navegador, $_COOKIE) y SESIONES (lado del servidor, $_SESSION) añaden una «memoria» entre páginas.
  • SESIONES = mecanismo SEGURO: datos del lado del servidor (no modificables), el navegador solo guarda un IDENTIFICADOR. Cookies = lado del cliente (modificables, para datos no sensibles).
  • AUTENTICACIÓN: conexión (comprobar contraseña, guardar la identidad en sesión) → páginas protegidas (comprobar la sesión) → desconexión (destruir).
  • SEGURIDAD (de alto riesgo): contraseñas con HASH (password_hash/verify, NUNCA en claro), regenerar el ID al conectarse, cookies seguras (HttpOnly/Secure/SameSite), HTTPS, control de accesos (autorización).

Reto 48h — aplique mañana

Construya una conexión mínima: un hash creado con password_hash, comprobación con password_verify, session_regenerate_id, almacenamiento de la identidad en sesión, una página protegida que redirige si no y una desconexión. Luego falsifique su cookie y constate que el acceso sigue denegado.

Lista de salida de la sección
  • Puedo explicar la diferencia cookie/sesión y decir dónde vive cada dato.
  • Sé construir una conexión con hash, sesión regenerada y página protegida.
  • He comprobado que una cookie falsificada no da ningún acceso.
Autoevaluación 1-5: ¿pongo cada dato del lado correcto (servidor frente a cliente)?¿rechazo toda contraseña en claro?

Preguntas frecuentes

Cookies o sesiones: ¿qué diferencia hay y cuál usar para qué?

Ambas dan una «memoria» a HTTP, pero de forma distinta. COOKIES: datos en el NAVEGADOR (lado del cliente), reenviados en cada petición — VISIBLES y MODIFICABLES por el usuario, tamaño pequeño, posible persistencia larga; nunca datos sensibles en claro (opciones HttpOnly, Secure, SameSite). SESIONES: datos del lado del SERVIDOR, el navegador solo guarda un IDENTIFICADOR; el usuario NO PUEDE modificar los datos; mayor capacidad; dura generalmente la visita. Las sesiones usan una cookie (para el identificador) pero los DATOS quedan en el servidor — esa es la diferencia clave. Use las SESIONES para el estado SENSIBLE (autenticación, cesta) — la opción por defecto; las COOKIES para preferencias NO sensibles y persistencia larga (idioma, tema). Proteja ambas (opciones de cookie, regeneración de identificador, HTTPS).

¿Cómo construir una autenticación correcta y qué trampas evitar?

Pasos: (1) INSCRIPCIÓN — validar, aplicar HASH con password_hash(), guardar el HASH (nunca el claro). (2) CONEXIÓN — recuperar el usuario por correo (consulta PREPARADA), comprobar con password_verify(), luego session_regenerate_id() y guardar la identidad en sesión. (3) PÁGINAS PROTEGIDAS — comprobar la sesión (isset($_SESSION['user_id'])), si no redirigir. (4) AUTORIZACIÓN — comprobar el DERECHO sobre ESE recurso, no solo la conexión. (5) DESCONEXIÓN — vaciar y luego destruir la sesión. Trampas graves: contraseñas en CLARO o mal cifradas (lo peor), ID no regenerado (fijación), cookies no seguras, sin HTTPS, autorización olvidada, mensajes de error que revelan correos, intentos ilimitados (fuerza bruta), consultas concatenadas (inyección SQL). En un PROYECTO REAL, privilegie los sistemas de autenticación PROBADOS de los frameworks.

Comprueba tu comprensión

¿Dónde se guardan los datos de una SESIÓN?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 2Preguntas inéditas y más difíciles para validar tus conocimientos