Manejo del tiempo de espera de la sesión del usuario en aplicaciones SaaS - discutiendo varios enfoques

11

Sé que esto tiene una gran posibilidad de ser marcado como duplicado, pero no pude encontrar exactamente lo que estoy buscando.

Este es un problema común y estoy seguro de que tiene una solución de mejores prácticas bien definida

Antecedentes

  1. Una aplicación SaaS de una sola página, tiene una gran cantidad de arrastrar y soltar, el usuario puede interactuar con ella sin mucha comunicación del servidor por períodos de tiempo

  2. La sesión del servidor solo contiene objetos de usuario, utilizando una cookie de sesión no persistente

  3. La sesión caduca en el servidor después de X horas

  4. Algunas cosas se cargan solo durante el inicio de sesión

Problema

  1. El usuario trabaja en la aplicación, cuando termina, el usuario no cierra la sesión, solo mantiene el navegador abierto
  2. El usuario regresa después de más de X horas (la sesión se invalida en el servidor)
  3. El usuario interactúa con la aplicación sin necesidad de una conexión de servidor (arrastra y suelta cosas, ediciones de texto ...)
  4. Solo en la siguiente interacción del servidor (supongamos que no hay guardado automático) el usuario es arrojado a la página de inicio de sesión y pierde parte de su trabajo

Soluciones posibles

Aquí hay algunas soluciones que tengo en mente, me gustaría saber si hay alguna otra, y si hay algo fundamentalmente malo con alguna de ellas.

1. Nunca desconecte al usuario

  • ¿Cómo? ya sea mantener una sesión larga, mantener una cookie persistente o hacer ping de Java Keep "mantener vivo"
  • Pros : el usuario no necesita preocuparse por nada, soluciona el problema por ellos
  • Contras : no es compatible con PCI, no es seguro y necesita cambios de desarrollo, por ejemplo, las cosas cargadas a la sesión solo en el inicio de sesión del usuario deben pasar a un submodelo de pub (escuchar los cambios de eventos) o tener un tiempo de espera de caché.

2. Almacenamiento local

  • ¿Cómo? use el nuevo almacenamiento local para almacenar temporalmente el estado si está desconectado, redirigir a la página de inicio de sesión, persistir una vez que haya iniciado sesión
  • Pros : También es base para el soporte de "trabajar sin conexión", no solo para manejar el tiempo de espera de la sesión
  • Contras : más difícil de implementar, es necesario hacer una fusión de estado del árbol de datos, no todos los navegadores admiten

3. Guardado automático

Cada acción del usuario que cambie el modelo debe persistir de inmediato (o mediante algún tipo de cola del lado del cliente), por ejemplo, si marcan una casilla de verificación, cambian un campo de texto o arrastran y sueltan algo, una vez que terminan, persisten los cambios.

  • ¿Cómo? Use un marco MV ** (Backbone.js / Knockout.js / Ember.js / Angular.js, etc.) para vincular el modelo y persistir en los cambios.
  • Pros : Parece una solución limpia, la sesión está activa mientras el usuario esté activo, no se realiza ningún trabajo del lado del cliente sin persistir.
  • Contras : la última acción que realiza el usuario después de perder el tiempo de espera de una sesión.

4. Cierre la sesión del usuario después de que expire la sesión

esto puede tener varios enfoques

  1. Pregúntele al servidor "ha caducado la sesión" - esto es un poco complicado 22 / El gato de Schrodinger, ya que la mera pregunta al servidor extiende la sesión (reinicia el tiempo de espera),

    • ¿Cómo? O tiene un servidor que admite esa pregunta (no sé de ninguno, pero vengo de Java Land) o, simplemente puede mantener una tabla de ID de sesión y el último tiempo de acceso manualmente, y preguntar al servidor pasando la sesión ID como parámetro en lugar de la cookie, no estoy seguro de si esto es posible, pero suena peligroso, inseguro y tiene un mal diseño. La página de inicio de sesión persiste una vez que ha iniciado sesión
    • Pros : si existiera tal soporte nativo en los servidores, parece una pregunta limpia y legítima (preguntar si el usuario X todavía tiene una sesión o no sin renovarla si es así)
    • Contras : si el servidor no lo admite (y, una vez más, no sé si algún servidor o marco tiene esta funcionalidad), entonces la solución alternativa tiene enormes riesgos de seguridad.
  2. Una solución alternativa que he escuchado es tener una sesión corta en el lado del servidor y un ping del lado del cliente para mantener vivo, que tiene un número máximo de pings

    • ¿Cómo? Sesión corta en el servidor, el cliente hace ping cada sesión TimeOut / 2, tiene reintentos máximos de Y.
    • Pros : tipo de soluciona el problema, rápido y sucio
    • Contras : se siente como un pirata informático, manejando la renovación de la sesión usted mismo en lugar de dejar que el servidor lo haga
  3. Temporizador del lado del cliente

    • ¿Cómo? Tenga un temporizador en el lado del cliente y sincronícelo con el servidor reiniciando en cada solicitud para que sea igual al tiempo de espera máximo de la sesión del servidor menos algo de relleno, después de que el usuario no envíe ninguna solicitud al servidor, la interfaz de usuario muestra un "sesión es a punto de terminar, ¿quieres continuar? " (como lo tiene en la banca en línea)

    • Pros : soluciona el problema

    • Contras : no se me ocurre ninguno, excepto la necesidad de asegurarme de que la sincronización funcione

La pregunta

Probablemente me estoy perdiendo algo en el análisis anterior, podría tener algunos errores tontos, y me gustaría su ayuda para corregirlos. ¿Qué otras soluciones puedo tener para esto?

Eran Medan
fuente
Uso angular y django con tastypie, así que aquí están mis pensamientos desde ese punto de vista: 4.1: La clase de autenticación utilizada para todos sus recursos podría verificar y comparar la diferencia horaria entre ahora y el valor del campo de "último acceso" en su Usuario modelo. 401 es el tiempo es mayor que el marco de tiempo configurado. 200 de lo contrario y actualice el campo 'último acceso' con now. 4.2 suena como una excelente manera de matar su servidor y aumentar los costos 4.3 En Android, cuando regrese a la pantalla de inicio, estoy bastante seguro de que el proceso está en pausa y que también podría interferir con el temporizador del lado del cliente.
airtonix

Respuestas:

5

Creo que la solución simple más común es establecer un temporizador en el extremo del cliente que muestre un mensaje después de que haya pasado una cierta parte de la ventana de tiempo de espera normal y luego los cierre a la fuerza justo antes de que la sesión expire de todos modos si no toman ninguna medida.

El almacenamiento local y el guardado automático introducen algunos problemas con las transacciones y lo que realmente significa guardar. He estado en bastantes proyectos en los que esto ha resultado ser más problemático de lo que vale cuando la base de usuarios no comprende la mecánica detrás de esto.

Nunca se puede cerrar sesión cuando las regulaciones lo permiten, pero lo lleva a cometer errores en los que no maneja correctamente lo que sucede si alguien cierra sesión inesperadamente, y todo el negocio estatal se vuelve un poco intenso de mantener si hay mucho para seguir un usuario "activo".

Cuenta
fuente
2

Una solución alternativa que he escuchado es tener una sesión corta en el lado del servidor y un ping de mantener> vivo al lado del cliente, que tiene un número máximo de

¿Cómo? Sesión corta en el servidor, el cliente hace ping cada sesiónTime / 2, tiene un máximo de reintentos de Y. Pros: Tipo de soluciona el problema, rápido y sucio Contras: Se siente como un hack, manejando la renovación de la sesión usted mismo en lugar de> dejar que el servidor lo haga

En mi opinión, esta es la mejor solución. ¿Por qué lo consideras un "truco sucio"?

Hace exactamente lo que hay que hacer. Mientras el usuario trabaja con el programa, la sesión permanecerá abierta.

Después de que el usuario se detenga para trabajar con el programa, la sesión se cerrará.

Suficientemente simple para ser implementado.

Exactamente lo que se necesita, si entendí bien la pregunta.

johnfound
fuente
A veces, los trucos sucios son las mejores soluciones :) gracias. Entendiste la pregunta perfectamente bien
Eran Medan
2

De hecho, estoy creando una aplicación que se ocupa de esto.

Comencé creando un servicio RESTful usando Django, Guradian y Tastypie. Se autentica utilizando APIKEY solamente, la autorización para los objetos es manejada por Guardian.

La aplicación django solo tiene una vista de plantilla urlconf que carga el archivo base.html que es ...

En el lado del cliente, creé una aplicación usando Angular.

En lo que respecta a la autenticación, hay un http-auth-interceptor que escucha las respuestas 401.

Cuando se recibe un 401, amortigua la solicitud saliente y dispara un evento "se requiere inicio de sesión". Esto puede ocurrir varias veces.

Tengo una ventana emergente modal que contiene un formulario de inicio de sesión que se presenta cuando se escucha el evento "inicio de sesión requerido", y realiza un inicio de sesión que devuelve un recurso de Usuario (un paquete JSON) que también contendría el APIKEY.

Todas las solicitudes almacenadas previamente que dieron como resultado una respuesta 401 se vuelven a reproducir con el APIKEY ahora incluido en el encabezado http de Autorización.

Utilizo otro servicio / fábrica angular para administrar los datos js del almacenamiento local, y ahí es donde almaceno el nombre de usuario y la apikey.

La única pieza del rompecabezas que queda por resolver es cómo asegurar esa información y cómo exigir un tiempo de espera en esa información.

Quizás use una verificación de marca de tiempo de la última solicitud http válida.

airtonix
fuente
Como seguimiento de esto, he considerado hacer la siguiente comparación en cada verificación de autenticación de tastypie: current_time> user.lastlogin_time + settings.SESSION_TIMEOUT. luego devuelve 401 si es verdadero. Cada autenticación válida actualiza user.lastlogin_time a current_time.
airtonix
Esto es bastante bueno y cómo también pensé en manejarlo.
oligofren
1

En mi caso, estoy usando algo similar a 4.1. Después de que el usuario inicie sesión, se produce una solicitud json de AJAX de conducción angular muy ligera a la API REST a intervalos establecidos contra el servidor. Debido a los requisitos de seguridad, la interfaz de usuario propietaria anticipa que el servidor mantendrá una sesión para el usuario que almacena cierta información protegida, plantillas, datos, etc. en el lado del servidor. Este sigue siendo mi método preferido desde una perspectiva de seguridad. Cuando se trata de datos confidenciales (no solo contraseñas con hash y demás), la OMI que la almacena del lado del cliente en el almacenamiento local, etc., presenta un mayor riesgo que el lado del servidor (estoy seguro de que alguien debatiría eso conmigo). Los terceros usan la misma API cuando se comunican con el sistema, pero deben enviar credenciales de autenticación en cada solicitud.

La sesión en el servidor tiene una vida útil máxima inactiva aplicada, y el motor de almacenamiento de la sesión está en memoria caché (que también tiene una vida útil máxima aplicada en ese momento, la sesión de memoria se marcará como vencida). La vida útil solo debe ser mayor que la vida útil de la sesión que abstraiga en su aplicación (y no tiene que ser mucho). Por ejemplo, es posible que la sesión no caduque hasta que haya estado inactiva durante 48 horas en lo que respecta al servidor, pero su código controla la vida útil real. Esto podría generar problemas de recursos si esa vida útil es demasiado grande y usted realiza un mal trabajo al administrar las sesiones.

En mi caso, diferentes usuarios pueden tener diferentes tiempos de espera inactivos de sesión en función de sus roles dentro de la organización. El servidor establece límites máximos en la vida útil de la sesión, pero siempre que los límites definidos por el usuario sean menores que esos, funciona bien. Una vez que el servidor caduca la sesión, es un problema discutible ya que el proceso de caducidad de la sesión ya habría sido manejado con gracia por la aplicación. Este es un requisito del tipo de aplicación comercial que construí.

Una vez que la sesión de los usuarios ha estado inactiva y se encuentra dentro del umbral especificado por la aplicación, la API le indicará a la interfaz de usuario que muestre un cuadro de diálogo de cuenta regresiva (como lo hacen los bancos), y una vez que esté dentro de un margen específico de distancia desde el vencimiento, lo hará con gracia. cierra la sesión del usuario. Esta funcionalidad persiste en las ventanas del navegador (porque el servidor tiene el control), y un evento inactivo en cualquier ventana comenzará el temporizador elegante y el proceso de cierre de sesión automático (y los mantendrá sincronizados).

Si, por casualidad, la sesión caduca de manera desagradable (las sesiones se vuelcan en memcached), la siguiente solicitud que afecte al servidor notificará al usuario y lo moverá de nuevo al punto de partida (rara vez ocurre, pero puede).

Chris
fuente