Franchement, cela crée trop de tracas dans la v1.0 pour avoir une fonctionnalité qui nécessite trois soumissions de formulaire, avec des données de session $_SESSION contenant tous les éléments intermédiaires - uniquement pour qu'un utilisateur démarre une opération, puis ouvre un deuxième onglet et effectuer une deuxième opération qui piétine les données de session.

Je doute que ce soit malveillant (mais je ne peux pas l'escompter). Il est plus probable que l'utilisateur démarre une opération, soit interrompu, oublie qu'il a commencé ou ne trouve pas l'onglet d'origine, il recommence donc (puis trouve plus tard l'onglet d'origine et essaie de terminer l'opération une deuxième fois).

Étant donné que je code en PHP, je peux détecter l'existence de données de session lors de la soumission du formulaire (comment pourrais-je le faire avec JS si l'utilisateur ouvre un autre onglet - je suppose que j'aurais besoin d'Ajax - non?).

Donc, chaque fois que je démarre une opération, je vérifie la présence d'un indicateur dans les données de session et si défini, je recharge à une page «Je suis désolé, Dave. continuer (en pensant à l'effacer à la fin de l'opération).

Je suppose que cela fonctionnerait, mais:
1) Est-il acceptable de limiter les applications du navigateur à un seul onglet / instance?
2) Dois-je tenter d'autoriser plusieurs instances dans la version 2.0?

D'autres commentaires, aide ou conseils?

5
Mawg says reinstate Monica 21 oct. 2011 à 06:41

5 réponses

Meilleure réponse

Une meilleure conception serait d'éviter de stocker l'état d'interaction de l'utilisateur dans la session. Mettez-le dans des champs de formulaire cachés ou quelque chose pour que chaque demande client porte son état associé. Si l'utilisateur s'inquiète de son altération, utilisez un HMAC pour éviter cela, et éventuellement le crypter s'il contient des éléments que l'utilisateur ne devrait pas voir.

Indiquez seulement que doit être partagé entre les onglets - comme l'identité de connexion de l'utilisateur, ou quelque chose comme un panier - doit être stocké dans la session.

5
Wyzard 21 oct. 2011 à 03:38

Tout au plus, vous pouvez conserver une liste de «dernière page demandée» dans le fichier de session, avec des indicateurs pour indiquer que l'utilisateur ne devrait pas être autorisé à le quitter s'il s'agit de l'un de ces indicateurs de forme critique. Donc, si vous êtes sur form.php et que c'est no-move-off, alors toute nouvelle page chargée devrait présenter une option "abandonner ou fermer la fenêtre".

Vous ne pouvez pas empêcher un utilisateur d'ouvrir un autre onglet / fenêtre, mais vous pouvez l'empêcher de se déplacer ailleurs dans votre site dans ces autres fenêtres / onglets.

Cependant, considérez qu'il s'agit d'une très mauvaise expérience utilisateur. Imaginez si Amazon vous a piégé dans la page du panier et ne vous a jamais laissé sur une autre page sans avoir à acheter réellement quelque chose. Pensez à mettre à jour votre code pour permettre à plusieurs fenêtres différentes d'utiliser le même formulaire.

4
Marc B 21 oct. 2011 à 03:09

Si je faisais cela maintenant, je coderais probablement une application AngularJs d'une seule page (bien que toute forme de Js le fasse).

Au démarrage, recherchez un indicateur dans le stockage local. S'il est défini, refusez de démarrer, avec un message approprié, sinon définissez le drapeau et exécutez l'application.

Bien sûr, un utilisateur malveillant pourrait le contourner, car il ne s'agit pas d'une vérification côté serveur, mais je refuserais simplement de prendre en charge une telle opération.

0
Mawg says reinstate Monica 10 mai 2017 à 08:11

Ajout du script ci-dessous après ma connexion (par exemple, dashboard.php)

<script>
$(document).ready(function()
{
    $("a").attr("target", "");
    if(typeof(Storage)              !== "undefined") 
    {
        sessionStorage.pagecount    =   1;
        var randomVal               =   Math.floor((Math.random() * 10000000) + 1); 
        window.name                 =   randomVal;
        var url                     =   "url to update the value in db(say random_value)";
        $.post(url, function (data, url)
        {
        });
    } 
    else 
    {
        var url                     =   "url to remove random_value";           
        $.post(url, function (data, url)
        {
            sessionStorage.removeItem('pagecount');
            sessionStorage.clear();
            window.location         =   'logout.php';
        });
    }    
});
</script>

Ajout du script ci-dessous dans l'en-tête dans le reste de mes pages - "random_value" vient de db pour cet utilisateur

<script>
$(document).ready(function()
{       
    $("a").attr("target", "_self");

    if(typeof(Storage)                      !== "undefined") 
    {
        if (sessionStorage.pagecount) 
        {
            if('<?=$random_value?>'         ==  window.name)
            {
                sessionStorage.pagecount    =   Number(sessionStorage.pagecount) + 1;
            }
            else
            {
                var url                     =   "url to remove random_value";           
                $.post(url, function (data, url)
                {
                    sessionStorage.removeItem('pagecount');
                    sessionStorage.clear();
                    window.location         =   'logout.php';
                });

            }               
        } 
        else 
        {           
            var url                         =   "url to remove random_value";           
            $.post(url, function (data, url)
            {
                sessionStorage.removeItem('pagecount');
                sessionStorage.clear();
                window.location             =   'logout.php';
            });
        }
    } 
    else 
    {   
        var url                             =   "url to remove random_value";                   
        $.post(url, function (data, url)
        {
            sessionStorage.removeItem('pagecount');
            sessionStorage.clear();
            window.location                 =   'logout.php';
        });
    }   
});
</script>
2
Steffi 21 juin 2016 à 13:04

Avec tous les navigateurs prenant en charge la navigation par onglets, ce serait une expérience utilisateur médiocre d'essayer de limiter la navigation à un seul onglet (vous pourriez aussi bien créer une application de bureau).

Vous pouvez résoudre ce problème en ajoutant un jeton CSRF à vos formulaires (en tant que variable masquée), qui serait soumis avec la demande.

Référence CSRF

Il existe de nombreuses façons de générer le jeton, mais essentiellement vous:

  1. créer le jeton
  2. stocker dans votre $_SESSION
  3. afficher le formulaire avec <input type="hidden" name="{token name}" value="{token value}" />

Ensuite, lorsque le formulaire est envoyé, vous cochez $_REQUEST['{token name}'] == $_SESSION[ {nom du jeton}] `.

Si ce jeton est différent, vous savez que ce n'était pas le formulaire que vous avez généré à l'origine et pouvez donc ignorer la demande jusqu'à ce que le formulaire réel arrive avec le bon jeton.

Une chose: si un attaquant peut comprendre comment vous générez vos jetons CSRF, il peut forger des requêtes.

2
Yzmir Ramirez 21 oct. 2011 à 03:15
7844415