防止双重HTTP POST

时间:2009-01-14 11:47:06

标签: post

我为注册活动制作了一个小应用程序。用户输入他们的数据并单击“登录”。

现在有时人们在数据库中是双倍的,完全相同的数据相互之后非常快地插入了2次。这只能意味着有人点击了按钮两次,这导致了两个帖子发生。

这是常见的网络问题,因为信用卡应用和论坛应用经常说:“点击一次就够了!”。

我猜您可以通过检查完全相同的数据来查看帖子是否唯一,但我想知道是否还有其他方法。

这个过程不适用于ASP.NET webforms,因为POST并不重要。

11 个答案:

答案 0 :(得分:22)

虽然JavaScript解决方案可以在单击后禁用提交按钮,但这对禁用JavaScript的用户没有任何影响。在添加之前,您应该始终在没有JavaScript的情况下正常工作,否则没有意义,因为用户仍然可以通过禁用JavaScript来绕过检查。

如果动态生成表单所在的页面,则可以添加包含某种序列号,散列或任何唯一的隐藏字段。然后,您将进行一些服务器端验证,以检查具有该唯一值的请求是否已经进入。当用户提交表单时,将根据“已使用”值列表检查唯一值。如果它存在于列表中,则它是一个欺骗请求,可以被丢弃。如果它不存在,则将其添加到列表中并正常处理。只要您确保该值是唯一的,这可以保证相同的表单不能提交两次。

当然,如果表单所在的页面不是动态生成的,那么您需要在服务器端以较难的方式执行此操作,以检查是否尚未提交相同的信息。

答案 1 :(得分:20)

到目前为止,大多数答案都是客户端的。在服务器端,您可以在第一次生成表单时生成带有GUID的隐藏字段,然后在收到帖子时将该GUID记录为提交的表单。在进行任何更多处理之前检查它。

答案 2 :(得分:4)

用户端解决方案是在第一次点击后通过Javascript禁用提交按钮。

它有缺点,但我发现它经常用在电子商务网站上。

但是,它永远不会取代真正的服务器端验证。

答案 3 :(得分:3)

客户端技术很有用,但您可能希望将其与某些服务器端技术结合使用。

执行此操作的一种方法是在表单中包含唯一标记(例如GUID或类似标记),以便在您处理表单时可以检查标记是否已被使用,防止双重提交。

在您的情况下,如果您有一个包含事件访问者的表,则可以将此标记包含在列中。

答案 4 :(得分:3)

仅有客户端的解决方案是不够的,正如许多答案中所述。您需要使用服务器端故障安全。

禁用提交按钮的常常被忽视的原因是,用户只需刷新提交目标(并在“您确定要重新提交POST数据吗?”对话框中单击“确定”)。或者甚至,当您尝试将页面保存到磁盘时,某些浏览器可能会隐式重新加载提交的页面(例如,您尝试保存订单确认的硬拷贝)。

答案 5 :(得分:2)

每当从服务器请求页面时,生成唯一的requestToken,将其保存在服务器端,将状态标记为NOT Processed并将其与当前请求的页面一起传递。现在,每当页面提交发生时,从“POST”ed数据中获取requestToken并检查状态并保存数据或采取其他操作。

大多数银行应用程序都使用这种技术来防止双重“POST”。所以这是经过时间验证的。防止双重提交的可靠方法。

答案 6 :(得分:1)

几乎没有人禁用js。 考虑为70岁的女性编写电子商务网站,双击每个链接和按钮。 你想要做的只是添加一个javascript,以防止她点击“立即订购”两次。 是的 - 在服务器端检查这个“是防御性的” - 但不要为这种情况编码。但是为了更好的用户界面,也可以在客户端进行。

以下是我发现的一些脚本:

//
// prevent double-click on submit
//
  jQuery('input[type=submit]').click(function(){
    if(jQuery.data(this, 'clicked')){
      return false;
    }
    else{
      jQuery.data(this, 'clicked', true);
      return true;
    }
  });

// Find ALL <form> tags on your page
$('form').submit(function(){
    // On submit disable its submit button
    $('input[type=submit]', this).attr('disabled', 'disabled');
});

答案 7 :(得分:1)

这些解决方案都没有解决负载均衡服务器问题。

如果您有一些负载均衡器,如果服务器不了解其他服务器,则向服务器发送UUID(或任何类型的唯一号码)以再次存储和读取将无法正常工作,因为每个请求都可以由无状态环境中的不同服务器。这些服务器需要读/写到同一个地方。

如果您有多台服务器,您需要在服务器之间安装一些共享缓存(如Redis),以便在同一位置读取/写入唯一值(可能是过度工程解决方案,但有效)。

答案 8 :(得分:0)

客户端更改是一种常见技术:

  • 禁用提交按钮
  • 将屏幕更改为“请稍候”屏幕
  • 如果表单是模态的,请将屏幕更改回常规过程(这样可以使内容看起来非常光滑)

但它并不完美。这一切都依赖于JS可用,如果不是这样,没有后端重复检测,你仍会得到重复。

所以我的建议是在幕后开发某种检测然后改进你的形式以阻止JS能够双重提交的人。

答案 9 :(得分:0)

您可以跟踪表单提交的次数,并将其与会话中包含表单的页面唯一访问次数进行比较。

答案 10 :(得分:0)

除了已经提到的许多好的技术之外,另一个简单的服务器端方法,其缺点是需要会话,是在第一次提交时关闭会话变量。