Gestion du délai d'expiration de la session utilisateur dans les applications SaaS - discussion de plusieurs approches


11

Je sais que cela a une grande chance d'être marqué comme doublon, mais je n'ai pas pu trouver exactement ce que je cherche

Il s'agit d'un problème courant et je suis sûr qu'il contient une solution de bonnes pratiques bien définie

Contexte

  1. Une application SaaS d'une seule page, a beaucoup de glisser-déposer, l'utilisateur peut interagir avec elle sans beaucoup de communication avec le serveur pendant des périodes de temps

  2. La session serveur contient uniquement l'objet utilisateur, à l'aide d'un cookie de session non persistant

  3. La session expire sur le serveur après X heures

  4. Certaines choses sont chargées uniquement lors de la connexion

Problème

  1. L'utilisateur travaille sur l'application, une fois terminé, l'utilisateur ne se déconnecte pas, laisse simplement le navigateur ouvert
  2. L'utilisateur revient après plus de X heures (la session est invalidée sur le serveur)
  3. L'utilisateur interagit avec l'application sans avoir besoin d'une connexion au serveur (fait glisser et laisse tomber des choses, modifications de texte ...)
  4. Seulement lors de la prochaine interaction avec le serveur (supposons qu'il n'y a pas de sauvegarde automatique), l'utilisateur est renvoyé à la page de connexion et perd une partie de son travail

Solutions possibles

Voici quelques solutions que j'ai en tête, j'aimerais savoir s'il y en a d'autres et s'il y a quelque chose de fondamentalement mauvais avec l'une d'entre elles.

1. Ne déconnectez jamais l'utilisateur

  • Comment? soit garder une longue session, garder un cookie persistant, ou ping "keep alive" javaScript
  • Avantages : l'utilisateur n'a besoin de s'inquiéter de rien, résout le problème pour lui
  • Inconvénients : non conforme PCI, non sécurisé et nécessite des modifications de développement, par exemple, les éléments chargés dans la session uniquement lors de la connexion de l'utilisateur doivent passer à un sous-modèle de publication (écoute des modifications d'événements) ou avoir un délai d'expiration du cache.

2. Stockage local

  • Comment? utiliser un nouveau stockage local pour stocker temporairement l'état en cas de déconnexion, rediriger vers la page de connexion, persister une fois connecté
  • Avantages : également une base pour la prise en charge du «travail hors ligne», pas seulement la gestion du délai d'expiration de la session
  • Inconvénients : plus difficile à mettre en œuvre, besoin de fusionner l'état de l'arborescence de données, tous les navigateurs ne prennent pas en charge

3. Sauvegarde automatique

Chaque action utilisateur qui modifie le modèle doit persister immédiatement (ou via une sorte de file d'attente côté client), par exemple, si elle coche une case à cocher, modifie un champ de texte ou fait glisser et déposer quelque chose, une fois qu'elles sont terminées, persiste les modifications.

  • Comment? Utilisez un framework MV ** (Backbone.js / Knockout.js / Ember.js / Angular.js, etc.) pour lier le modèle et persister sur les modifications.
  • Avantages : semble une solution propre, la session est active tant que l'utilisateur est actif, aucun travail côté client n'est effectué sans le persister.
  • Inconvénients : la dernière action que l'utilisateur effectue après la fin d'un délai d'expiration de session.

4. Déconnectez l'utilisateur après l'expiration de la session

cela peut avoir plusieurs approches

  1. Demandez au serveur "la session a expiré" - c'est un peu un problème avec le chat de Schrodinger, car la simple question au serveur prolonge la session (redémarre le délai),

    • Comment? Soit avoir un serveur qui prend en charge une telle question (je n'en connais pas, mais je viens de Java) ou, on peut simplement garder une table des ID de session, et le dernier temps d'accès manuellement, et demander au serveur en passant la session ID en tant que paramètre au lieu du cookie, je ne sais pas si cela est même possible, mais cela semble dangereux, peu sûr et de mauvaise conception quelle que soit la page de connexion, persistez une fois connecté
    • Avantages : S'il y avait une telle prise en charge native sur les serveurs, cela ressemble à une question claire et légitime (demander si l'utilisateur X a toujours une session ou non sans la renouveler si c'est le cas)
    • Inconvénients : si le serveur ne le prend pas en charge (et encore une fois, je ne sais pas si un serveur ou un framework possède cette fonctionnalité), la solution de contournement présente potentiellement d'énormes risques de sécurité.
  2. Une solution de contournement que j'ai entendu est d'avoir une courte session côté serveur et un ping côté client en vie, qui a un nombre maximal de pings

    • Comment? Session courte sur le serveur, le client envoie une requête ping à chaque sessionTimeOut / 2, avec un nombre maximal de tentatives de Y.
    • Avantages : sorte de résoudre le problème, rapide et sale
    • Inconvénients : se sent comme un hack, gérer le renouvellement de la session vous-même au lieu de laisser le serveur le faire
  3. Minuterie côté client

    • Comment? Ayez un temporisateur côté client et synchronisez-le avec celui du serveur en le redémarrant à chaque demande pour qu'il soit égal au délai d'expiration de la session serveur maximale moins un remplissage, après que l'utilisateur n'envoie aucune demande au serveur, l'interface utilisateur affiche une "session est sur le point d'expirer, voulez-vous continuer? " (comme vous l'avez fait sur les services bancaires en ligne)

    • Avantages : résout le problème

    • Inconvénients : Je ne peux penser à aucun, sauf au besoin de s'assurer que la synchronisation fonctionne

La question

Il me manque probablement quelque chose dans l'analyse ci-dessus, je pourrais avoir des erreurs stupides, et j'aimerais votre aide pour les corriger. Quelles autres solutions puis-je avoir pour cela?


J'utilise angular et django avec tastypie alors voici mes réflexions de ce point de vue: 4.1: La classe d'authentification utilisée pour toutes vos ressources pourrait vérifier et comparer le décalage horaire entre maintenant et la valeur du champ "dernier accès" sur votre utilisateur modèle. 401 est le temps est supérieur au délai configuré. 200 sinon et mettez à jour le champ «dernier accès» avec now. 4.2 semble être un excellent moyen de tuer votre serveur et d'augmenter les coûts 4.3 Sur Android, lorsque je reviens à l'écran d'accueil, je suis presque sûr que le processus est en pause et que cela pourrait également interférer avec le minuteur côté client.
airtonix

Réponses:


5

Je pense que la solution simple la plus courante consiste à définir un minuteur côté client qui affiche un message après qu'une certaine partie de la fenêtre de délai normal se soit écoulée, puis les déconnecte de force juste avant l'expiration de la session de toute façon s'ils ne prennent aucune mesure.

Le stockage local et la sauvegarde automatique présentent certains problèmes avec les transactions et ce que signifie réellement la sauvegarde. J'ai participé à de nombreux projets où cela s'est avéré être plus problématique que cela ne vaut lorsque la base d'utilisateurs ne comprend pas les mécanismes derrière.

La déconnexion ne peut jamais se faire là où la réglementation le permet, mais cela vous conduit à des erreurs où vous ne gérez pas correctement ce qui se passe si quelqu'un est déconnecté de manière inattendue, et toutes les affaires de l'État deviennent un peu intensives à maintenir s'il y a beaucoup à suivre. un utilisateur "actif".


2

Une solution de contournement que j'ai entendu est d'avoir une courte session côté serveur, et un ping côté client keep> alive, qui a un nombre maximum de

Comment? Session courte sur le serveur, le client envoie une requête ping à chaque sessionTime / 2, a max> nouvelles tentatives de Y. Pour: sorte de résoudre le problème, rapide et sale Contre: se sent comme un hack, gérer le renouvellement de la session vous-même au lieu de laisser le serveur le faire

C'est à mon avis la meilleure solution. Pourquoi considérez-vous cela comme un "hack sale"?

Il fait exactement ce qui doit être fait. Pendant que l'utilisateur travaille avec le programme, la session reste ouverte.

Une fois que l'utilisateur a cessé de travailler avec le programme, la session sera fermée.

Assez simple pour être implémenté.

Exactement ce qui est nécessaire, si j'ai bien compris la question.


Parfois, les hacks sales sont les meilleures solutions :) merci. Vous avez parfaitement compris la question
Eran Medan

2

Je suis en train de créer une application qui traite de cela.

J'ai commencé par créer un service RESTful en utilisant Django, Guradian et Tastypie. Il s'authentifie en utilisant uniquement APIKEY, l'autorisation aux objets est gérée par Guardian.

L'application django n'a qu'une seule vue de modèle urlconf qui charge le base.html qui est ...

Côté client, j'ai créé une application utilisant Angular.

En ce qui concerne l'authentification, il existe un intercepteur http-auth qui écoute 401 réponses.

Lorsqu'un 401 est reçu, il met en mémoire tampon la demande sortante et déclenche un événement "connexion requise". Cela peut se produire plusieurs fois.

J'ai une fenêtre contextuelle modale contenant un formulaire de connexion qui est présenté lorsque l'événement "connexion requise" est entendu, et il effectue une connexion qui renvoie une ressource utilisateur (un ensemble JSON) qui contiendrait également l'APIKEY.

Toutes les demandes mises en mémoire tampon qui ont précédemment abouti à une réponse 401 sont réexécutées avec l'APIKEY désormais inclus dans l'en-tête http d'autorisation.

J'utilise un autre service / usine angulaire pour gérer les données json de stockage local, et c'est là que je stocke le nom d'utilisateur et l'apikey.

La seule pièce du puzzle qui reste à résoudre est de savoir comment sécuriser ces informations et comment appliquer un délai d'expiration sur ces informations.

Utilisez peut-être une vérification d'horodatage de la dernière demande http valide.


En guise de suivi, j'ai envisagé de faire la comparaison suivante pour chaque vérification d'authentification de type de dégustation: current_time> user.lastlogin_time + settings.SESSION_TIMEOUT. puis retournez 401 si vrai. Chaque authentification valide met à jour user.lastlogin_time en current_time.
airtonix

C'est assez sympa et comment j'ai aussi pensé à le gérer.
oligofren

1

Dans mon cas, j'utilise quelque chose de similaire à 4.1. Une fois que l'utilisateur s'est connecté, une requête json AJAX pilotée angulairement très légère est envoyée à l'API REST à des intervalles définis par rapport au serveur. En raison des exigences de sécurité, l'interface utilisateur propriétaire prévoit que le serveur maintiendra une session pour l'utilisateur qui stockera certaines informations protégées, modèles, données, etc. côté serveur. C'est toujours ma méthode préférée du point de vue de la sécurité. Lorsque vous traitez des données sensibles (pas seulement des mots de passe hachés et autres), le stockage par l'OMI du côté client dans le stockage local, etc. pose un plus grand risque que du côté serveur (je suis sûr que quelqu'un en discuterait avec moi). Les tiers utilisent la même API lors de la communication avec le système, mais doivent envoyer des informations d'authentification à chaque demande.

La session sur le serveur a une durée de vie maximale inactive qui lui est appliquée, et le moteur de stockage de session est memcached (qui a également une durée de vie maximale appliquée à quel point la session de mémoire sera marquée comme expirée). La durée de vie ne doit être supérieure à la durée de vie de la session que vous résumez dans votre application (et ne doit pas nécessairement être la mienne). EG La session peut ne pas expirer tant qu'elle n'a pas été inactive pendant 48 heures en ce qui concerne le serveur, mais votre code contrôle la durée de vie réelle. Cela pourrait entraîner des problèmes de ressources si cette durée de vie est trop longue et que vous ne faites pas un bon travail de gestion des sessions.

Dans mon cas, différents utilisateurs peuvent avoir différents délais d'inactivité de session en fonction de leurs rôles au sein de l'organisation. Le serveur place des limites maximales sur la durée de vie de la session mais tant que les limites définies par l'utilisateur sont inférieures à celles-ci, cela fonctionne très bien. Une fois que le serveur a expiré la session, c'est un problème théorique car le processus d'expiration de la session aurait déjà été géré par l'application avec élégance. Il s'agit d'une exigence du type d'application métier que j'ai créée.

Une fois que la session des utilisateurs a été inactive et se trouve dans un seuil spécifié par l'application, l'API demandera à l'interface utilisateur d'afficher une boîte de dialogue de compte à rebours (comme le font les banques), et une fois qu'elle se trouve dans une marge de distance spécifique dans le temps à compter de l'expiration, elle gracieusement déconnecte l'utilisateur. Cette fonctionnalité persiste dans toutes les fenêtres du navigateur (car le serveur est sous contrôle), et un événement inactif sur n'importe quelle fenêtre commencera la minuterie gracieuse et le processus de déconnexion automatique (et les gardera synchronisés).

Si, par hasard, la session expire de manière ingrate (les sessions sont vidées sur memcached), la prochaine demande qui affecte le serveur avisera l'utilisateur et le ramènera à la case départ (arrive rarement, mais peut).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.