11
votes

Sécurité de printemps - Demande simultanée pendant la déconnexion

Nous utilisons la sécurité du ressort dans notre application Web. La plupart des pages sont sécurisées, c'est-à-dire un utilisateur DOIT être connecté pour accéder à ces pages. Cela fonctionne bien généralement. Cependant, nous rencontrons un comportement indésirable lors de la déconnexion.

Supposons qu'un utilisateur soit connecté et envoie une demande auprès de la page de frappe pour charger une page (sécurisée). Avant que cette demande soit terminée, le même utilisateur envoie une demande de déconnexion (c'est-à-dire une demande avec servle_path "/ j_spring_security_logout"). La demande de déconnexion est généralement très rapide et elle peut être complétée plus tôt que la demande précédente. Bien sûr, la demande de déconnexion efface le contexte de sécurité. Par conséquent, la requête précédente perd le contexte de sécurité au milieu de sa vie et cela provoque généralement une exception.

En fait, l'utilisateur n'a pas besoin de démarrer la première demande "manuellement". Ce scénario peut arriver sur une page avec une actualisation automatique, c'est-à-dire que l'utilisateur appuie sur le lien de déconnexion, une fraction de seconde après une actualisation a été envoyée automatiquement.

d'un point de vue, cela peut être considéré comme un comportement significatif. D'autre part, je préférerais empêcher une telle perte de contexte de sécurité au milieu de la vie d'une demande.

Y a-t-il un moyen de configurer la sécurité du printemps pour éviter cela? (Quelque chose comme "Effacement du contexte de sécurité au cours de laquelle il existe d'autres demandes concurrentes de la même session" ou "lisez le contexte de sécurité une seule fois lors d'une seule demande et mettez-le en cache pour une utilisation supplémentaire")

merci.


2 commentaires

Je suis sûr que je vois aussi le même comportement dans mon application. Malheureusement, tout ce qui a essayé jusqu'à présent n'a pas corrigé ( @Authentiollingprincipal méthode param, principale méthode param, SecurityContexTholder.getContext (). GetAuthentication () sont null une fois qu'une déconnexion simultanée est terminée)


En cliquant sur le bouton de déconnexion redirige vers votre page de déconnexion dans un scénario normal?


3 Réponses :


14
votes

Donc, c'est tout (sans surprise) par conception. Ces Sécurité du ressort Docs donne une bonne explication quant à ce qui se passe - citant:

Dans une application qui reçoit des demandes simultanées en une seule session, la même instance SecurityContext code> sera partagée entre les threads. Même si un threadlocal code> est utilisé, il s'agit de la même instance extraite du httpsession code> pour chaque thread. Cela a des implications si vous souhaitez modifier temporairement le contexte sous lequel un thread est en cours d'exécution. Si vous utilisez simplement SecurityContexTholder.getContext () CODE> et appelez SETUuthentication (anauthentication) code> sur l'objet contextuel renvoyé, l'objet code> authentification code> changera Tous les threads simultanés qui partagent le même SecurityContext Code> instance. Vous pouvez personnaliser le comportement de SecurityContextPersSistenceFilter code> pour créer un tout nouveau SecurityContext CODE> pour chaque demande, empêchant ainsi les modifications d'un thread de l'affectation d'une autre. Sinon, vous pouvez créer une nouvelle instance juste au point où vous modifiez temporairement le contexte. La méthode SecurityContextholder.createempontextextextex () code> renvoie toujours une nouvelle instance de contexte. P> blockQuote>

Un extrait de la citation ci-dessus dit: P>

... Vous pouvez personnaliser le comportement de SpringContextPersistenceFilter code> ... p> blockQuote>

Malheureusement, les DOC ne fournissent aucune information sur la manière de faire cela, ni comment il serait même approché. Ce Donc, question demande la chose même (essentiellement, est une version distillée de cette question), mais il n'a pas reçu beaucoup d'attention. P>

Il y a aussi ce Réponse qui fournit un peu plus de profondeur dans le fonctionnement interne de httpsessionsecurityContextrepository code>, qui est susceptible d'être la pièce qui devrait être ré-écrite / Mis à jour afin de s'attaquer à ce problème. P>

Je mettrai à jour cette réponse si je viens de résoudre ce problème (comme la création d'une nouvelle instance du contexte) dans la mise en œuvre. P>

MISE À JOUR H2>

La racine du problème que je ressens était liée à la lecture d'un attribut d'identifiant de l'utilisateur hors du httpsession code> (après avoir été effacé par une "déconnexion simultanée" " demander). Au lieu d'implémenter mon propre SpringContextrepository Code> J'ai décidé de créer un filtre simple qui enregistre l'authentification code> actuelle code> à la demande, puis travaillez à partir de là. P>

Voici Le filtre de base: p> xxx pré>

qui doit être ajouté après le SecurityContextPersSenseFilter code> En ajoutant ce qui suit à votre WebSecurityConfigurierAdapter code> Configurer (HTTPSececurity HTTP) CODE> Méthode. P>

http.addFilterAfter(new SaveAuthToRequestFilter(), SecurityContextPersistenceFilter.class)


0 commentaires

3
votes

Disclaimer: le comportement en question a été mis en œuvre à dessein. Et si quelqu'un décide de le désactiver, ils devraient lire SEC-2025 que décrit le problème que vous obtenez en retour. b>


Si je comprends bien cela correctement, le problème est que la déconnexion efface les données authentification de SecurityContext de SecurityContext CODE> rendant ainsi P>

private boolean clearAuthentication = true;


1 commentaires

Je pense que la question dans sec-2025 ne doit pas être prise légèrement. Voir la FIX COMMIT qui illustre succinctement le problème: Github.com/spring-Projects/ Spring-Security / Commit / ...



3
votes

Votre exigence a été signalée comme un bogue (pas une demande de fonctionnalité) dans jira SEC-2025 . Et ils l'ont réparé au printemps 3.2, alors que vous attendez ici pour arriver / résoudre implicitement l'empêche de son conception.

Le comportement par défaut consiste à enregistrer le SecurityContext dans le httpsession et c'est la seule implémentation de la sécurité de printemps AFAIK fournit en ce moment.

Même le SecurityContext est threadlocal Il partage la même chose qui se trouve dans le httpsession . Donc, lorsque SecurityContext est nettoyé, il supprimera du httpsession , par conséquent ne sera pas disponible de la session de l'utilisateur entière.

Ce que vous devez faire est, stockez le SecurityContext en outre dans httpServletQuest (ou quelque chose de lié à la requête HTTP) autre que le httpsession et lisez-le de httpsession et si non trouvé, lisez-le à partir de httpServletQuest . Assurez-vous d'enregistrer une copie de de SecurityContext dans le httpservletQuest . Lorsque vous vous déconnez-vous, nettoyez le SecurityContext seulement de httpsession qui se produit actuellement. Dans ce cas, quels que soient les threads d'exécution (liés aux demandes http) auront accès au SecurityContext via httpservletQuest (si ce n'est pas trouvé dans httpsession - ce qui vous arrive en ce moment) même si l'utilisateur s'est déconnecté. Les nouvelles demandes HTTP suivantes auront besoin d'une authentification car les nouvelles demandes n'ont aucun SecurityContext dans le httpsession (ou httpservletQuest ).

Gardez une nouvelle copie de SecurityContext dans chaque httpServletRQest peut être une surcharge uniquement pour adresser un boîtier d'angle.

Pour faire cela, vous devez lire et comprendre après des implémentations de printemps.

  1. httpsessionsecurityContextrepository classe

    SecurityContextPersisTenceFilter Utilisations SecurityContextrepository Pour charger et enregistrer SecurityContext . HTTPSessIsIsecurityContextrepository est une implication de SecurityContextrepository .

  2. SavetosessionResponsewrapper classe

    Et vous devrez peut-être remplacer ci-dessus 2 classes en fournissant vos propres implémentations ou en remplacement des implémentations nécessaires. (Et il peut aussi d'autres aussi)

    Voir:

    • httpsessionsecurityContextrepository: loadContext () -> lit le contexte de sécurité
    • httpsessionsecurityContextrepository: Savecontext () -> Enregistre la sécurité Conext

      Mise en œuvre de la méthode.

      Je pense que les documents de Spring Security Docs mentionne clairement de ne pas traiter httpsession . C'est pourquoi il y a un SecurityContext .

      IMO collez simplement sur les implémentations de sécurité de printemps lorsqu'il n'y a aucune recommandation des ingénieurs de Spring Security pour faire quelque chose par vous-même. Ce que je serre ici peut ne pas corriger, et assurez-vous qu'il n'y aura pas de trous de sécurité et il ne devrait pas casser les autres cas d'utilisation lorsque vous effectuez des modifications non recommandées uniquement pour couvrir un boîtier d'angle. Je ne ferai jamais cela si cela m'est arrivé, car il est la conception que les experts en sécurité du printemps ont décidé d'aller avec beaucoup de nombreux faits de sécurité que je n'ai aucune idée du tout.


4 commentaires

sec-2025 ne directement carte de ce problème depuis que le ticket fait référence à l'enregistrement accidentel d'un utilisateur de retour dans ; Alors que voici ici, nous sommes confrontés au problème où un thread se retrouve "déconnecté" même s'il a commencé comme "connecté". Cela étant dit, votre réponse ressemble à un bon moyen de s'attaquer.


@JLB Vous devez comprendre que, avec cela, vous obtiendrez essentiellement une copie en lecture seule que vous savez que vous savez exister, ce qui signifie qu'aucun code de sécurité de printemps n'utilisera. Et si c'est ce que vous voulez, la question de toute la question est discutable, vous pouvez créer un filtre simple qui stockera le contexte dans la demande / thread local et obtenir le même résultat.


@chimmi Vous avez absolument raison - je me suis rendu compte cela peu de temps après avoir accepté la prime. J'ai une idée que je vais mettre à jour ma réponse avec bientôt - je crois que c'est une approche plus propre, bien que cela soit pris en charge de mon problème.


@chimmi j'ai mis à jour ma réponse avec une solution simple. Cela me traite spécifiquement, mais je pense que cela s'appliquerait à la plupart des cas.