PHP:在按下 Back 时阻止表单被意外重新处理

Posted

技术标签:

【中文标题】PHP:在按下 Back 时阻止表单被意外重新处理【英文标题】:PHP: Stop a Form from being accidentally reprocessed when Back is pressed 【发布时间】:2009-10-29 21:54:41 【问题描述】:

当用户点击后退按钮时,阻止表单被重新处理的最佳方法是什么?

我正在关注Post/Redirect/Get pattern,所以如果按 F5 我没有问题,但返回按钮仍然提供重新提交表单的机会。如果此表单是信用卡处理页面,那就不好了。

有人问过这个问题here,但措辞和答案质量很差,并不完全针对这个问题。

我有 form.php 提交给自己。如果提交时输入数据没有错误,用户将被重定向到 form_thanks.php。重新提交 form.php(糟糕!)后回击(和“发送”或“重新提交”),然后将它们带回 form_thanks.php。

如果可能,还请包括不涉及使用会话的解决方案。

【问题讨论】:

为什么要在没有会话的情况下实现这个?您可能需要某种类型的服务器端存储来检测重复的帖子。 见下文,我建议将令牌存储在数据库中,以及它是否已被使用。这绝对是某种类型的服务器端存储,而不是会话。 【参考方案1】:

我会以不同的方式来做。设置一个以随机字符串为值的隐藏输入,并在提交时将该随机字符串存储在会话中。设置一个简单的检查,看看他们是否已经发布了它,以及他们是否不接受输入。

【讨论】:

【参考方案2】:

这应该使用一次性令牌或nonce 来完成。 php/server 应该在一个隐藏的表单域中包含这个标记。

它应该存储所有最近令牌的列表,并且每次提交表单时,它应该检查令牌是否在最近的有效令牌列表中。

如果它不在列表中,则不要重新处理表单。 如果它在列表中,则处理表单并从列表中删除令牌。

令牌可以在会话中处理,也可以在没有会话的简单数据库表中处理。不过,令牌应该是特定于用户的。

这也是避免CSRF 攻击的推荐方法。

【讨论】:

嗯,我很惊讶你能在 SO 上回答你自己的问题。应该很可能只是 UPDATE 您的主要问题来包含解决方案。 “问和回答你自己的问题也很好”(meta.***.com/faq),有人建议我在别人的回答似乎没有完全回答问题时这样做。最好在单独的问题/答案中执行此操作,因为这样其他人可以专门评论/投票,否则原始“问题”会让找到它的人感到困惑,因为它不再是一个问题。【参考方案3】:

只是在这里大声思考。但是对于 post/redirect/get 的变化,最终获取实际上不是最终获取;)相反,它总是自动转发到真正的最终页面,因此如果用户点击后退按钮,他们会返回他们从哪里来的?

编辑:

好的,考虑到 OP 的评论,这是另一个想法。可以使表单提交的 URL 需要一个仅适用于一次用途的参数。该令牌将在提交表单之前生成(使用 MD5 或类似的),并且可以存储在数据库中(响应其他人的建议,您在不使用会话的情况下请求解决方案)。处理完表单后,此令牌将在数据库中标记为已被使用。这样当页面返回时使用相同的token,可以采取措施防止表单数据重新提交到后端。

【讨论】:

除了浏览器的后退按钮通常有下拉菜单可以让用户轻松地向后跳两页或更多页之外,这将起作用。 根据我的第二个建议,每次在没有令牌参数的情况下请求 URL 时,都会生成一个令牌,并且表单本质上会重定向到自身,但将此令牌作为 URL 的一部分。希望这是有道理的,我从早上 5:30 就起床了;) 为了这个问题页面,也许有人应该标记一个涉及会话和无会话数据库令牌的综合答案。 菲尔:你自己总是可以这样回答问题【参考方案4】:

迟到的答案,但可以通过使用基于 AJAX 的解决方案完全避免处理;在此处理方案中包含随机数不会有问题,但是通过使用异步查询,成功后重定向用户,不会通过刷新、按下或单击按钮以外的任何方式重复请求。

通过嵌入到请求的处理程序中(无论是使用 PrototypeJS 或 jQuery 的高级还是低级与您的手动功能级别)分别在请求完成和首次触发时启用和禁用按钮的机制。

【讨论】:

这也很有意义【参考方案5】:

我发现返回会使表单回到页面被重定向之前的状态,如果是这种情况,有一个隐藏的输入/变量或以值开头的东西说真,然后一旦提交表单,如果值为true,则将其更改为false然后提交,否则返回false

【讨论】:

你能确认这在所有浏览器中都以同样的方式工作吗?【参考方案6】:

试试这个:

<SCRIPT type="text/javascript">
    window.history.forward();
</SCRIPT>

【讨论】:

这是一个 PHP 问题,不是 javascript。 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 我已经在我的在线考试页面(PHP)中尝试了上述代码。这阻止了后退按钮的操作,我知道禁用后退按钮的规则是违反规则的。如果考生可以返回并再次回答问题(在在线考试的情况下),那是没有意义的。它对我有用。

以上是关于PHP:在按下 Back 时阻止表单被意外重新处理的主要内容,如果未能解决你的问题,请参考以下文章

Vue常用修饰符

Razor 页面搜索表单在按下后退按钮时不保留旧值

HTML: JavaScript: 阻止表单提交和调用 Javascript 函数

在按下Datagridview的特定列上的EnterKey时,将打开新表单

覆盖后退按钮以充当主页按钮

如何防止活动在按下按钮时加载两次