如何在服务器端处理多个提交

How to handle multiple submissions server-side

提问人:Paolo Bergantino 提问时间:10/20/2008 最后编辑:Paolo Bergantino 更新时间:4/2/2014 访问量:16788

问:

我们都知道“禁用提交按钮”的古老技巧,但是处理服务器端多个提交的最佳方法是什么?我有一个应用程序,其中表格只发送一次是绝对关键的 - 它处理信用卡。我没有写现在的情况,但作为一个快速修复,我使用了提交时禁用技术,但是一些禁用了 javascript 的不耐烦的用户仍然被收取两次费用。

那么,有哪些方法可以避免这种情况呢?我能想到一些 - 我过去使用过一些 - 但我想看看是否有任何关于如何解决这个问题的“最佳实践”。我正在使用 PHP,但我对概念更感兴趣。

编辑:我知道令牌技术,这是我过去使用过的技术,这个问题或多或少是为了看看我的方法是否与你们其他优秀程序员使用的方法一致。

服务器端

评论

1赞 RB. 10/21/2008
当然,共识似乎是,这就是我们其他优秀程序员(和我!)使用的:-)它是一种功能强大且稳健的技术,在大多数应用程序中都具有安全优势。
1赞 Rontologist 10/21/2008
这类似于问题<a href=“stackoverflow.com/questions/130337/...您是否阻止用户在网站上多次发布数据</a>。

答:

32赞 RB. 10/20/2008 #1

一种真正有效的方法是在请求的同时提交令牌,并保留已用令牌的列表。如果令牌无效,或者令牌已被处理,则中止。

令牌可以像递增整数一样简单,存储在隐藏的文本字段中,也可以对其进行加密以提高安全性。通过在创建页面时生成令牌,对其进行加密,然后确认令牌已生成且尚未处理,可以使此功能更加可靠。

评论

2赞 JeremyWeir 8/20/2010
如何处理用户按下后退按钮(大多数浏览器不会重新请求)、更改表单中的数据并再次提交相同的令牌?
0赞 abel 10/7/2010
@jayrdub我知道这个 q 是针对 RB 的,但我只是给出一个错误,说会话已过期,然后引导他们回到表单,加载表单字段和会话中保存的数据以减少用户的不便
0赞 Adam 7/26/2019
我看到一些人建议将令牌存储在会话中,然后将令牌与它进行比较,如果相等,则取消设置会话并继续请求,否则在船上。我认为这仍然容易受到提高条件的影响,对吧?您是否建议将“使用过的代币列表”存储在数据库中并检查交易是否存在?
0赞 James T 11/4/2022
我尝试了隐藏的输入令牌解决方案,但它不起作用,因为如果我在提交后返回,某些字段(包括隐藏的输入令牌)将被重置,这意味着它将被视为新提交。我不知道为什么有些输入被重置,而有些输入被保留。
11赞 David 10/20/2008 #2

在隐藏的表单字段中包含随机唯一令牌。然后在后端,您可以检查它之前是否提交过。

这通常是一个好主意,因为它也可以帮助您防御 XSS 攻击。

评论

1赞 Matthew 8/29/2017
这就是我在我的网站上所做的;JavaScript 用一个随机的 32 个字符的字符串填充一个隐藏字段,我检查它之前是否提交过。这也适用于禁用 JS 时,因为我检查该字段是否为空。但是,是什么阻止了某人检查元素并粘贴到 32 个字符的字符串中?
0赞 TalesMGodois 1/11/2023
我真的认为这一定是最好的解决方案,在生成表单时需要生成 req I
3赞 ripper234 10/21/2008 #3

我不会为此依赖任何客户端。为什么不在向客户端显示提交按钮之前为此事务服务器端生成一个唯一 ID?然后,客户端必须重新提交此令牌,并检查服务器端是否每个令牌都提交过一次。

正如其他人所说,令牌可以是递增整数(+ 用户名)或 GUID。

9赞 Keith Lawrence 10/21/2008 #4

您也可以简单地测试在最后一分钟(或第二秒,取决于服务器的延迟)是否进行了相同的交易。大多数人不会使用同一张卡在一分钟内购买两本相同的书(或其他任何东西)。如果您在最后一分钟保留了信用卡付款的缓存,并检查您即将进行的付款是否与您刚刚完成的付款相同(相同的卡号,相同的金额),那么您很可能会发现重复的付款。

-7赞 Jake Wilson 9/7/2011 #5

无需生成唯一的代币和所有这些爵士乐。表单验证通过后,只需将访问者重定向到另一个页面,上面写着“您的信用卡正在处理中”之类的内容。如果访问者重新加载页面,他们正在重新加载重定向的页面,而不是 POST 提交。

评论

5赞 Clement Herreman 1/24/2013
错。如果我疯狂地点击提交按钮,您将收到多个 POST 请求。
0赞 Jake Wilson 1/25/2013
您是否考虑过在有人单击提交按钮后但在提交表单之前禁用它?这将使某人无法多次实际单击该按钮。他们唯一能做到的方法是,如果他们故意使用 Chrome 开发工具或 Firebug 来更改客户端 HTML 和脚本,以便多次提交。典型的用户不会有这样做的知识或愿望。
3赞 Clement Herreman 1/25/2013
客户端不足以防止严重错误,例如向客户端收取两次(或更多)费用。如果上次部署的 js 文件版本出现错误,并且该按钮未被禁用,因为该错误没有执行 javascript,该怎么办?那些禁用 javascript 的人,并不总是出于选择,比如视障人士(见 stackoverflow.com/a/2905104/135494)。“所有这些爵士乐”对于普通网站来说可能已经足够了,但 OP 表示“表格只发送一次是绝对关键的”,如果没有“爵士乐”,那么这还不够。
0赞 Adam 7/26/2019
PGR 模式可防止页面重新加载,但不能防止双击。
0赞 NateShumate 4/2/2014 #6

我也有类似的问题。读完这篇文章后,我认为代币可能是要走的路。这篇文章展示了一个很好的实现示例。