解决双重提交问题

时间:2011-01-15 11:36:27

标签: web-applications web-frameworks double-submit-prevention

我想看看Web开发人员如何避免双重提交问题。基本上我对这个问题的理解如下:

当不耐烦的用户多次提交表单时会发生双重提交,从而导致出现问题。这个问题可以通过JavaScript(特别是jQuery脚本)来修复,这些脚本在提交表单后禁用了提交按钮 - 这样做的一个弱点就是客户端禁用了JavaScript。

还有服务器端检测方法。

所以我的问题是:

人们如何克服双重提交? 什么是双重提交引起的问题的真实例子? 任何Web应用程序框架都内置了双重提交工具吗?

7 个答案:

答案 0 :(得分:16)

现实生活情况:在博彩网站上下注。用户双击并获得两次下注。不好! Javascript检查不足以阻止这种情况。

解决方案:

  1. 使用呈现表单的服务器端脚本语言在表单中创建UUID / GUID隐藏输入。

  2. 在表单提交上,立即将其添加到名为UniqueSubmissions的数据库表中(例如)。然后继续处理。

  3. 如果在UniqueSubmissions表中找到,则会拒绝具有相同UUID / GUID的每个后续请求。

  4. 这对我们有用。希望有助于回答您的问题!

答案 1 :(得分:8)

如果您正在使用java服务器端脚本并使用struts 2,那么请参考此链接,该链接讨论使用令牌。

http://www.xinotes.org/notes/note/369/

当请求与令牌第一次一起提交时,应该生成令牌并保存在初始页面呈现的会话中,在struts动作中运行带有线程名称作为令牌ID的线程并运行逻辑客户端请求,当客户端再次提交相同的请求时,检查线程是否仍在运行(thread.getcurrentthread()。中断)如果仍在运行,则发送客户端重定向503。

请查看struts 2code的ExecuteAndWaitInterceptor,这个结合token的逻辑将有助于快速点击

答案 2 :(得分:7)

使用redirect-after-post或有时称为PRG (post/redirect/get)

简而言之,当用户发布表单时,您执行客户端重定向(在使用发布数据后)到响应(成功)页面。

答案 3 :(得分:5)

一个真实的例子就是这个答案发布两次;-)。 如果您不想依赖客户端的任何方面(javascript,甚至cookie),您可以计算提交数据的MD5哈希值,可能通过添加源IP和使用的浏览器等信息,并拒绝帖子具有相同的哈希值。

答案 4 :(得分:3)

web2py框架针对双重表单提交built-in protection。它在会话中以及表单中的隐藏字段中存储一次性令牌,并且它们必须在提交时匹配或拒绝提交。此方法也protects against CSRF(跨站点请求伪造)。

答案 5 :(得分:2)

如果表单的目的是提供用于在服务器dbms中保存某些数据的接口,则可以使用对提交的数据必需的特殊修订字段。检查提交的修订是否与数据库中数据的最新版本(或者是要插入的新数据的版本)相匹配,可以很好地控制如果提交多个提交内容该怎么做按顺序。

答案 6 :(得分:1)

使用struts web-application框架我们可以按如下方式处理这个问题:

Struts有3种方法用于token, saveToken(), isTokenValid() and resetToken()

saveToken() - 生成令牌密钥并保存到请求/会话属性 isTokenValid() - 在请求/会话中针对1商店验证提交的令牌密钥  resetToken() - 重置令牌密钥。

工作原理:
1)加载表单后,在操作类上调用saveToken()以创建和存储令牌密钥。 Struts会将生成的密钥存储在请求/会话中。如果成功创建了令牌,当浏览器上的查看源您将看到类似于以下内容的内容时,令牌密钥将存储为隐藏字段:

<form action="myaction.do" method="post"> 
 <input type="hidden" 
 name="<%= Constants.TOKEN_KEY %>" 
 value="<%= session.getAttribute(Action.TRANSACTION_TOKEN_KEY) %>" > 

2)表单提交后,在动作类上调用isTokenValid(),它将使用之前存储在请求/会话中的令牌密钥验证提交的令牌密钥(隐藏字段)。如果匹配,则返回true。

public final ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
    saveToken(request);
    if (!tokenIsValid(request)) {
        //forward to error page saying "your transaction is already being processed" 
    } else {
        //process action 
        //forward to jsp 
    }
    // Reset token after transaction success. 
    resetToken(request);
}

reference