Tema representativo de entrevista

Entrevista de Backend: ¿Cómo diseñas una gestión segura de sesiones web?

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Diseña la gestión de sesiones para una aplicación web B2B de dos regiones. Utiliza sesiones del lado del servidor, admite acceso normal y de administrador, cierre de sesión en un dispositivo, cierre de sesión en todos los dispositivos y revocación por cambio de contraseña. Un cierre de sesión global debe surtir efecto en cinco segundos. Explica el identificador de sesión, la cookie, el registro del servidor, la rotación en el inicio de sesión y el cambio de privilegios, la expiración por inactividad y absoluta, la autorización, la consistencia de revocación, la observabilidad y las pruebas de seguridad.

Planteamiento y contexto aplicable

Diseña la gestión de sesiones para una aplicación web B2B de dos regiones. Los navegadores utilizan sesiones del lado del servidor para el acceso normal y de administrador. El producto necesita cierre de sesión en el dispositivo actual, cierre de sesión en todos los dispositivos y revocación tras un cambio de contraseña. Un cierre de sesión global debe rechazar las solicitudes protegidas en ambas regiones en un plazo de cinco segundos.

Para este ejercicio, elige un identificador opaco de 256 bits, un tiempo de expiración por inactividad de 30 minutos y un tiempo de expiración absoluto de 12 horas. Estas son decisiones del escenario, no constantes de seguridad universales. Explica qué cambia en el inicio de sesión, la elevación a administrador, la expiración, el cierre de sesión y ante un evento de sospecha de robo. Incluye solicitudes concurrentes y propagación entre regiones en lugar de describir únicamente los atributos de las cookies.

Esta es una pregunta sobre el ciclo de vida en el backend. Un diseño sólido mantiene el token del navegador sin significado intrínseco, convierte al servidor en la autoridad del estado de autenticación, rota la identidad a través de los cambios de límites de confianza y puede demostrar que las credenciales antiguas dejan de funcionar. Secure, HttpOnly y SameSite son importantes, pero ninguno de ellos por sí solo proporciona expiración, autorización o revocación del lado del servidor.

Lo que evalúa el entrevistador

La primera señal es si el candidato trata un identificador de sesión como una credencial de portador (bearer) temporal. Debe ser impredecible, aceptarse a través de un único mecanismo previsto, protegerse en tránsito y en reposo, y estar ausente de URLs y registros. Un lector de bases de datos o de logs no debería obtener automáticamente un token utilizable.

La segunda señal es el razonamiento sobre el ciclo de vida. El identificador anónimo no debe simplemente pasar a estar autenticado. El inicio de sesión y la elevación de privilegios cruzan límites de confianza, por lo que la aplicación crea un nuevo identificador y destruye el anterior. La expiración por inactividad y la absoluta son impuestas por el servidor. Limpiar una cookie del navegador es una limpieza en el cliente; no revoca una copia que ya posea un atacante.

La tercera señal es la distinción entre autenticación y autorización. Una sesión válida localiza a un usuario y un contexto de autenticación. Cada solicitud sigue comprobando la pertenencia al tenant y los permisos actuales. Copiar roles en un registro de sesión de larga duración sin una regla de invalidación puede preservar el acceso después de que un administrador elimine un rol.

La cuarta señal es la consistencia distribuida. La promesa de que el cierre de sesión global surta efecto en cinco segundos requiere una versión fidedigna o un estado de revocación con autoridad, obsolescencia de caché acotada y un comportamiento definido durante una partición. Decir "eliminarlo de Redis" es incompleto cuando otra región puede continuar utilizando un resultado positivo almacenado en caché.

La señal final es la verificación. El candidato debe convertir la fijación, el robo, CSRF, la expiración, la rotación concurrente, el retraso de réplica y las fugas en logs en casos ejecutables. Las afirmaciones de seguridad se vuelven creíbles cuando cada identificador antiguo tiene un evento específico tras el cual las solicitudes que lo utilicen deben fallar.

Preguntas para clarificar antes de responder

  • ¿Qué clientes están dentro del alcance? Esta respuesta apunta a una aplicación de navegador en el mismo sitio (same-site). Las aplicaciones nativas y

los clientes de API de terceros suelen necesitar un transporte y ciclo de vida de tokens diferentes.

  • ¿Qué significa "en cinco segundos"? El servidor debe rechazar solicitudes protegidas para entonces. Una pestaña del navegador

puede seguir mostrando contenido obsoleto hasta su siguiente solicitud.

  • ¿Se permiten sesiones simultáneas? Este diseño permite varios dispositivos y almacena cada sesión

por separado. Un producto más estricto puede limitarlas o reemplazar sesiones más antiguas al iniciar sesión.

  • ¿Qué eventos lo revocan todo? El cierre de sesión global y el cambio de contraseña incrementan una época (epoch) de sesión para toda la cuenta.

Un cambio de permisos puede incrementar una versión de autorización sin cerrar necesariamente la sesión en cada dispositivo.

  • ¿Qué tan riesgoso es el acceso de administrador? Este diseño rota en la elevación y registra la robustez

de la autenticación. Las operaciones de alto impacto también pueden requerir una reautenticación reciente.

  • ¿Debe funcionar el inicio de sesión entre sitios (cross-site) o la incrustación? SameSite=Lax se adapta a la navegación de origen primario asumida.

Un flujo legítimo entre sitios necesita una excepción estrecha más una protección CSRF explícita.

  • ¿Qué sucede durante una partición regional? El requisito de seguridad de cinco segundos implica un comportamiento fail-closed (cerrar el acceso en caso de fallo)

para rutas de alto riesgo cuando no se puede obtener un estado de revocación actualizado.

Estructura de respuesta en 30 segundos

"Colocaría un valor opaco de 256 bits en una cookie __Host- con Secure, HttpOnly, Path=/ y una política SameSite explícita, mientras almaceno únicamente una clave de búsqueda derivada por HMAC en el servidor. La fila de sesión contiene el usuario, el tenant, la robustez de la autenticación, marcas de tiempo de creación y actividad, expiraciones, y las versiones de sesión y autorización del usuario. El inicio de sesión y la elevación a administrador emiten atómicamente una nueva sesión e invalidan el identificador anterior. Cada solicitud protegida aplica la expiración por inactividad y absoluta, la época actual de la cuenta y la autorización vigente. El cierre de sesión revoca la fila; cerrar sesión en todos o el cambio de contraseña incrementa la época de la cuenta y publica la invalidación en ambas regiones con un límite de caché de cinco segundos. Verificaría la fijación, la reutilización de IDs antiguos, la rotación concurrente, CSRF, los límites de tiempo de expiración, el retraso regional y la redacción en logs".

Análisis detallado paso a paso

Comienza con el modelo de amenazas. Un atacante puede establecer un identificador antes de que la víctima inicie sesión, robar uno del navegador o la infraestructura, reproducirlo desde otro dispositivo, mantenerlo activo, explotar un permiso obsoleto o competir con una rotación. El sistema también debe resistir solicitudes de cambio de estado entre sitios porque los navegadores envían cookies automáticamente.

Utiliza la implementación de sesiones revisada del framework en lugar de inventar un generador y analizador aleatorios. Para el diseño planteado, genera 32 bytes aleatorios con un generador criptográficamente seguro. Envía el valor opaco sin procesar únicamente en la cookie. Deriva una clave de búsqueda de longitud fija como HMAC-SHA-256(server_key, raw_id) antes de consultar el almacenamiento, de modo que una copia de seguridad o snapshot de la base de datos no contenga los valores de portador. La rotación de claves para ese HMAC necesita un plan explícito de migración de doble lectura.

Un registro ilustrativo del servidor es:

text
session_lookup_key
user_id, tenant_id
created_at, last_seen_at
idle_expires_at, absolute_expires_at
authentication_time, authentication_strength
session_epoch, authorization_version
revoked_at, revocation_reason

El navegador recibe una cookie exclusiva del host (host-only) como:

text
Set-Cookie: __Host-session=<opaque>; Secure; HttpOnly; SameSite=Lax; Path=/

El prefijo __Host- requiere Secure, omite Domain y utiliza Path=/, lo que reduce la inyección de cookies en subdominios. HttpOnly bloquea las lecturas directas desde JavaScript, pero no impide que un script inyectado ejecute acciones autenticadas. SameSite reduce algunas solicitudes entre sitios, pero actúa como defensa en profundidad; las rutas de cambio de estado siguen utilizando un token CSRF u otra prueba vinculada a la solicitud y validan Origin según corresponda.

Acepta la sesión únicamente desde la cookie. Rechaza los identificadores proporcionados mediante parámetros de URL o encabezados alternativos a menos que un protocolo de cliente independiente los defina explícitamente. Las URLs se filtran a través del historial, encabezados Referer, analítica, capturas de pantalla y registros de proxy. Valida la sintaxis del token y realiza un manejo de errores de forma constante, al tiempo que limitas la tasa (rate limiting) de identificadores inválidos repetidos.

Mantén separados el estado anónimo y el autenticado. Cuando las credenciales sean correctas, crea una nueva sesión autenticada en una transacción corta e invalida el identificador previo al inicio de sesión. Ante una elevación a administrador u otro incremento de privilegios, exige la prueba adecuada, crea otro identificador nuevo e invalida el identificador de menor confianza. La respuesta establece la nueva cookie solo después de que el estado en el servidor se haya confirmado (commit).

Las solicitudes paralelas del navegador hacen que la rotación sea sutil. Si el identificador antiguo se destruye inmediatamente, una solicitud en tránsito puede recibir una respuesta no autorizada. Una transición acotada puede mapear el identificador antiguo al sucesor ya creado durante unos pocos segundos, pero nunca debe generar múltiples sucesores ni devolver el nuevo valor de portador a una repetición arbitraria. Utiliza un único registro atómico de rotación y haz que el sucesor esté disponible únicamente a través de la respuesta legítima. Para elevaciones altamente sensibles, aceptar un breve reintento es más seguro que una ventana de gracia amplia.

En cada solicitud protegida, busca la sesión, rechaza una fila revocada, aplica ambos relojes de expiración utilizando la hora del servidor y compara session_epoch con la época actual de la cuenta. El tiempo de expiración por inactividad de 30 minutos se desplaza únicamente ante actividad significativa y puede actualizarse en bloques (buckets) para evitar una escritura en cada solicitud. El límite absoluto de 12 horas nunca se desplaza. Las cuentas regresivas en el cliente mejoran la usabilidad, pero no deciden la validez.

Luego, carga la pertenencia al tenant y el estado de autorización actuales, o compara una versión cuyo contrato de invalidación sea explícito. Una sesión válida nunca reemplaza la autorización a nivel de objeto. Los cambios de dirección IP, red, dispositivo y User-Agent son señales de riesgo útiles; vincularse rígidamente a ellos provoca cierres de sesión falsos detrás de redes móviles, proxies y dispositivos compartidos. Los cambios de alto riesgo pueden activar una reautenticación o revocar la sesión según la política.

El cierre de sesión en el dispositivo actual marca atómicamente esa sesión como revocada antes de expirar la cookie. El cierre de sesión en todos los dispositivos y el cambio de contraseña incrementan el session_epoch del usuario; todas las sesiones más antiguas fallan entonces, incluso si las filas individuales persisten. Publica la nueva época en ambas regiones e invalida las cachés positivas. Limita la vida útil de la caché a un máximo de cinco segundos y haz que las rutas de administrador u otras de alto riesgo lean el estado con autoridad cuando la caché esté obsoleta. Durante una partición, esas rutas aplican fail-closed porque la disponibilidad no puede anular la garantía de revocación establecida.

No prometas un límite de cinco segundos sin medirlo. Registra el tiempo de confirmación fidedigno y el primer tiempo de rechazo observado en cada región. Genera alertas cuando la propagación se acerque al límite presupuestado. Audita la creación de sesiones, la rotación, la elevación, la expiración y la revocación con un ID de correlación no secreto; nunca registres cookies sin procesar, claves de búsqueda ni encabezados Cookie completos.

Diseña pruebas en torno a las transiciones. Establece una cookie anónima elegida por el atacante, inicia sesión y demuestra que no puede acceder a la cuenta. Repite IDs previos al inicio de sesión, previos a la elevación, con sesión cerrada, expirados y previos al cambio de contraseña. Ejercita los límites exactos de inactividad y absolutos con un reloj del servidor controlado. Ejecuta en carrera dos solicitudes de elevación, retrasa la invalidación en una región, simula una partición, envía solicitudes entre sitios e inspecciona cada registro de aplicación, proxy, rastreo (tracing), analítica y soporte en busca de valores de portador.

Ejemplo de respuesta de alta calidad

"Modelaría una sesión como una máquina de estados del lado del servidor cuyo identificador en el navegador es una credencial de portador temporal. Para este escenario, el identificador son 32 bytes aleatorios. La cookie es host-only, segura, HTTP-only, para toda la ruta (path-wide) y explícitamente SameSite=Lax; el almacén de sesiones recibe únicamente una clave de búsqueda derivada por HMAC.

El registro contiene el usuario y el tenant, la robustez de autenticación, marcas de tiempo de creación y última actividad, un límite de inactividad de 30 minutos, un límite absoluto fijo de 12 horas y copias instantáneas (snapshots) de la época de sesión de la cuenta y la versión de autorización. Cada solicitud verifica la fila, ambos límites de tiempo, la época actual y la autorización vigente. Los cambios de IP y dispositivo alimentan decisiones de riesgo en lugar de actuar como pruebas de identidad frágiles.

El inicio de sesión y la elevación a administrador crean cada uno una nueva sesión e invalidan el identificador de menor confianza. La rotación es atómica para que las solicitudes paralelas no puedan crear sucesores en competencia. El cierre de sesión primero revoca la fila del servidor y luego borra la cookie. El cierre de sesión en todos los dispositivos y el cambio de contraseña incrementan la época de la cuenta y publican invalidaciones de caché. Ambas regiones limitan la antigüedad de la caché positiva a cinco segundos; las rutas de alto riesgo aplican fail-closed si no pueden actualizar el estado.

Finalmente, probaría la fijación, la repetición de cada identificador anterior, CSRF, la rotación concurrente, los límites de inactividad y absolutos, los cambios de autorización, la propagación regional, el comportamiento en particiones y logs libres de secretos. La prueba clave es que cada evento de cambio de confianza tiene una credencial antigua definida y un punto medido tras el cual esa credencial es rechazada".

Errores comunes

  • Mantener el mismo ID tras el inicio de sesión → un atacante puede preseleccionarlo y esperar la autenticación →

emite una nueva sesión autenticada y destruye la anónima.

  • Limpiar únicamente la cookie al cerrar sesión → una copia robada sigue siendo válida → **revoca el estado del servidor antes

de limpiar el estado del cliente.**

  • Tratar HttpOnly como protección contra XSS → el código inyectado aún puede enviar solicitudes autenticadas →

previene XSS y aplica defensas de autorización y CSRF de forma independiente.

  • Usar SameSite como único control contra CSRF → excepciones legítimas y comportamientos del navegador debilitan la

suposición → utiliza pruebas CSRF vinculadas a la solicitud para cambios de estado.

  • Poner el ID en una URL → el historial, las cabeceras Referer y los registros copian la credencial → **acéptalo únicamente mediante

el mecanismo de cookie previsto.**

  • Renovar solo la expiración por inactividad → un robo activo puede durar para siempre → aplica un límite absoluto fijo.
  • Almacenar en caché una sesión válida indefinidamente → el cierre de sesión global no puede cumplir su límite → **controla por versiones las sesiones y

limita o elude las cachés positivas.**

  • Incrustar roles para siempre en la sesión → los permisos eliminados sobreviven → **comprueba la autorización actual

o una versión deliberadamente invalidada.**

  • Vincularse rígidamente a la dirección IP → los cambios normales de red desconectan a los usuarios → **utiliza los cambios de contexto como

señales de riesgo.**

  • Añadir un amplio período de gracia para la rotación → dos credenciales de portador siguen siendo útiles → **utiliza una transición atómica y

estrechamente acotada o acepta un reintento para elevaciones sensibles.**

  • Registrar encabezados de cookies para depuración → la observabilidad se convierte en un almacén de credenciales → **registra únicamente un

valor de correlación no secreto.**

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Por qué usar sesiones del lado del servidor en lugar de un JWT autocontenido?

La revocación global requerida ya necesita un estado del servidor actualizado. Un identificador opaco mantiene las declaraciones (claims) fuera del navegador y hace que la revocación de una sola fila sea sencilla. Un JWT puede funcionar, pero el cierre de sesión inmediato aún requiere una expiración corta, una lista de revocación o una búsqueda de la versión de la cuenta; la firma por sí sola no lo resuelve.

Pregunta de seguimiento 2: ¿Cómo evitas una escritura en cada solicitud para la expiración por inactividad?

Mantén el valor autorizado de última actividad en bloques (buckets) gruesos, por ejemplo, actualizando solo cuando el valor almacenado tenga varios minutos de antigüedad. El servidor sigue rechazando la solicitud cuando el plazo de inactividad derivado ha pasado. Elige el bloque de modo que su extensión máxima esté contemplada en la política de seguridad, y prueba ese límite explícitamente.

Pregunta de seguimiento 3: ¿Qué pasa si el almacén entre regiones no está disponible?

Separa el riesgo de las rutas. Las rutas públicas y de solo lectura pueden aceptar una decisión en caché acotada si la política lo permite. Las rutas de administrador y otras de alto impacto deben obtener un estado de época actualizado o aplicar fail-closed, ya que de lo contrario la promesa de cierre de sesión global en cinco segundos es falsa. Haz un seguimiento de esto como un SLO de disponibilidad y seguridad.

Pregunta de seguimiento 4: ¿Debería habilitarse siempre la renovación periódica del ID de sesión?

No. La renovación puede reducir la vida útil de un identificador robado, pero introduce condiciones de carrera en la transición y no reemplaza la expiración por inactividad o absoluta. Rota en el inicio de sesión y en los cambios de privilegios primero. Añade renovación periódica solo con un protocolo atómico probado y un beneficio claro en el modelo de amenazas.

Pregunta de seguimiento 5: ¿Cómo le mostrarías a un usuario sus dispositivos activos?

Almacena metadatos no secretos como la hora de creación, el bloque de actividad reciente, una etiqueta aproximada del dispositivo y ubicación aproximada. Permite al usuario revocar una fila o incrementar la época de la cuenta para todas. Las etiquetas son pistas, no pruebas de identidad del dispositivo, y los identificadores de sesión sin procesar nunca entran en la interfaz de usuario ni en las exportaciones de auditoría.

Pregunta de seguimiento 6: ¿Qué prueba única expone mejor la fijación de sesión?

Comienza con un identificador elegido antes de la autenticación, completa el inicio de sesión y luego envía una solicitud protegida usando el valor antiguo desde otro cliente. Debe fallar mientras que el identificador recién emitido tiene éxito. Repite el proceso para la elevación a administrador y verifica que el almacenamiento y los logs no revelen el nuevo token de portador de reemplazo.

Fuentes públicas

Preguntas relacionadas