如何将我的应用限制为单个浏览器标签页?

5
坦白地说,在v1.0中,要求三次表单提交的功能会带来太多麻烦,其中$_SESSION会话数据保存了所有中间内容,只是为了让用户开始操作,然后打开第二个选项卡并执行第二个操作,这些操作都会覆盖会话数据。
我怀疑这不是恶意行为(但不能排除)。更有可能的是,用户开始操作,被打断,忘记他们开始或找不到原始选项卡,所以再次开始(然后稍后找到原始选项卡并尝试第二次完成操作)。
由于我正在使用PHP编码,可以在表单提交时检测会话数据的存在(如果用户打开其他选项卡,我该如何使用JS进行检测 - 我想我需要Ajax对吗?)。
因此,每次开始操作时,我都会检查会话数据中的标志,如果设置了,我就重新加载到“对不起,Dave。我害怕那样做”页面,否则我将设置标志并继续(记得在操作结束时清除它)。
我想这样会起作用,但是:
1)将浏览器应用程序限制为单个选项卡/实例是否可接受?
2)我应该在v2.0中尝试允许多个实例吗?
还有其他的评论、帮助或建议吗?

如果您遇到此问题,那么您可能还会遇到用户单击浏览器的“返回”按钮,然后与之前的页面进行交互,即使没有多个选项卡也是如此。您不能假设 $_SESSION 始终与浏览器同步。 - Wyzard
5个回答

5
更好的设计是避免在会话中存储用户交互状态。将其放入隐藏表单字段或类似位置,以便每个客户端请求都携带其关联状态。如果您担心用户篡改它,请使用HMAC来防止并可能加密它(如果它包含用户不应该看到的内容)。
只有应该在选项卡之间共享的状态,例如用户的登录身份或像购物车之类的东西,应该存储在会话中。

4
您最多只能在会话文件中保留“最后请求页面”列表,并使用标志指示如果它是这些关键表单标志之一,则不允许用户离开该页面。因此,如果您在form.php上,并且它是一个no-move-off,则加载任何新页面时应呈现“中止或关闭窗口”选项。
您无法防止用户打开另一个选项卡/窗口,但可以防止他们在其他窗口/选项卡中移动到您站点的其他位置。
但请考虑,这是非常糟糕的用户体验。想象一下,如果亚马逊将您困在购物车页面上,除非您实际购买某些东西,否则永远不允许您进入其他页面。考虑更新您的代码以允许多个不同的窗口使用同一表单。

顺便问一下,其他人是如何处理这个问题的?由于会话数据是跨浏览器的,如果用户在同一浏览器的两个选项卡或窗口中并行执行相同的多阶段操作 - 共享相同的会话数据,会发生什么? - Mawg says reinstate Monica
@Mawg:只需将中间数据存储在表单的隐藏字段中即可(请参阅Wyzard的答案)。 - icktoofay

2

在登录后(比如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>

我在其他页面的头部添加了以下脚本 - “random_value”是该用户从数据库中获取的

<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
随着每个浏览器都支持选项卡式浏览,试图限制只能使用一个选项卡进行浏览会给用户带来贫乏的体验(这种情况下你不如开发一个桌面应用程序)。
你可以通过在表单中添加CSRF令牌(作为隐藏变量)来解决这个问题,该令牌将随请求一起提交。 CSRF 参考文献 有很多方法可以生成令牌,但基本上你需要:
  1. 创建令牌
  2. 将其存储在 $_SESSION
  3. 输出表单,并包含以下代码:<input type="hidden" name="{token name}" value="{token value}" />
然后当表单提交时,你需要检查 $_REQUEST['{token name}'] == $_SESSION[{token name}]`。
如果该令牌与原始令牌不同,则说明这不是由你生成的表单,因此你可以忽略该请求,直到真正的表单带有正确的令牌出现。 请注意:如果攻击者能够找出你的CSRF令牌生成方式,则可以伪造请求。

看起来我表达问题不太对。浏览器可以打开任意数量的标签页,但只有一个是我的。 - Mawg says reinstate Monica

0
如果我现在要做这个,我可能会编写一个单页AngularJs应用程序(尽管任何形式的Js都可以)。
启动时,在本地存储中查找标志。如果设置了,则拒绝启动,并显示适当的消息,否则设置标志并运行应用程序。
当然,恶意用户可能会绕过它,因为它不是服务器端检查,但我会拒绝支持这种情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接