如何防止表单在 5 分钟内多次提交?

Posted

技术标签:

【中文标题】如何防止表单在 5 分钟内多次提交?【英文标题】:How can I prevent a form from being submitted more than once within 5 minutes? 【发布时间】:2012-01-11 04:41:45 【问题描述】:

我最近发现我的 PM 系统存在一个巨大的安全问题,它允许用户通过地址栏中的 for 循环发送任意数量的消息。有人把这个放到地址栏中:

javascript:for(x=0;x<10000;x++) $('#compose form').submit(); 

消息被发送了 1000 次给我,我的收件箱里塞满了相同的消息,我的数据库太满了,以至于 phpMyAdmin 非常滞后。

我的问题是,我该如何防止这种情况发生?这是一个主要问题。

此外,表单是使用 AJAX 提交的。

编辑:

我使用 PHP,那么如何防止这种情况发生?就像我怎样才能做到每 5 分钟左右只能发送一条消息,如果他们在 5 分钟内提交了多个消息,它将显示错误(或者根本不显示任何用户反馈并阻止它被提交)?

【问题讨论】:

你不能用客户端代码解决这个问题。必须在服务器上完成。 你无法控制浏览器中发生的事情;如果你想防止这种情况发生,你需要在服务器端进行。考虑用一个专注于此的问题来代替它。 删除了我的答案...你们都是对的所有验证都应该在客户端和服务器端完成... 您需要使用您使用的相关服务器技术重新标记您的问题,以便找到合适的服务器端解决方案。 @Nathan,如果我不得不猜的话,我会说他们按照最初的要求对您的问题投了反对票,并且没有回来再看一眼。不幸的是,如果您后来投票反对的问题/帖子被编辑了,*** 不会给您任何通知。 【参考方案1】:

有一种明显的解决方法,问题不在于客户端 - 它在于服务器端

您的服务器脚本不应允许过于频繁地发送消息 - 例如。通常比说,每 10 分钟一次。为此,您可以在服务器端使用会话机制,并在用户发送电子邮件时保存信息。如果用户尚未发送电子邮件,您还应该将该信息保存在会话中 - 以区分启用会话的人和禁用会话的人(并且您应该完全阻止后者发送电子邮件)。

会话的实现方式(具体代码)取决于您用于服务器端脚本的语言(PHP、Python、JSP 等)。

【讨论】:

每十分钟一次的限制似乎过于严格。也许服务器处理可以将 duplicate 消息限制为每五分钟一条,同时将 unique 消息限制为每分钟一条 - 或类似的东西。 @nnnnnn:这真的取决于我们谈论的网站是什么。如果这是个人网站,每天有几十次点击和一份联系表格,那么我相信 10 分钟不会太严格。这实际上取决于单个用户是否需要在几分钟内发送多封电子邮件。还有另一个问题:OP 可以接受的电子邮件接收频率是多少(如果这是例如每小时 100 封电子邮件,因为它们是针对员工之间的,那么限制不应该像我那样严格建议的)。还认为发送大量独特的电子邮件并不难 最好将限制反转为每小时不超过 x 条消息,而不是根据单个消息之间的最短时间进行限制。这将在不给“正常”合法用户带来不便的情况下解决问题。 OP提到了他的“PM系统”,所以我假设他在谈论某种论坛/讨论类型的网站,普通用户可能合理地期望在十分钟内发送十几条或更多短信,但不能合理地期望保持连续几个小时这样做。 @nnnnnn:关于 PM 系统的好点,我错过了。无论如何,我在原始答案中提出每 10 分钟一次,因此应该将其视为时间段,而不是发送消息之间的差异(实际上是因为使用 cronjobs 更容易清除此类数据)。但我认为它不会“在不给“正常”合法用户带来不便的情况下解决问题”——他们必须将其视为“正常”用户不应该向其他人发送垃圾邮件。他们应该理解(参见 SO 机制)。正如我之前所说的周期长度(或电子邮件之间的中断)应该根据 OP 的需要进行调整,这很难猜测 我认为每 3-5 分钟(当然,每个用户)发送 1 或 2 条消息就可以了。只要他们不能一次发送一堆电子邮件,那就很好。我想知道 Stack Overflow 是如何限制评论投票的。【参考方案2】:

如果有人知道对你这样做,你可能无法在客户端做任何事情,所以我要说的唯一选择是你记录或保留请求数量的计数等(也许是特定的资源)并拒绝特定用户的请求(或发送“忙碌”的 http 代码等)。

我认为最简单的方法是计算来自特定 IP 地址的请求(这显然有缺点,例如代理或 NAT 后面的多个用户等)。

实际的解决方案将取决于您的服务器端语言和 Web 服务器,但您或许可以制定一个规则并看看它是如何工作的。每个 IP 地址每分钟 5 个请求(或任何适合您使用的请求)。

【讨论】:

【参考方案3】:

正如其他人所说,您必须在服务器上实施保护。再多的客户端编码都无法提供保护。

保护服务器免受此类滥用的常用方法称为rate limiting。您决定希望给定客户端能够提交消息的频率,并且您对服务器进行编码以忽略任何超出该限制的消息。

例如,您可以决定每分钟不超过一条消息,每 10 分钟不超过两条消息,一小时不超过四条消息。您可以选择您认为合理的任何内容,然后根据该算法编写代码。

在您的服务器中,您必须能够识别消息来自哪个用户(很可能通过身份验证 cookie),并且在您的数据库中,您必须能够找出最后一条消息的时间由该用户发送。您甚至可以将该信息缓存在服务器的 RAM 中(取决于您的服务器的工作方式)以避免对每个请求进行数据库查找,因为您只需要保留最近的信息并且您只需要对屡犯者进行性能优化(那些试图滥用您的服务器并因此最近才发送请求的人)。

【讨论】:

【参考方案4】:

我同意每个人发布的关于速率限制的内容。

但是,这在服务器端实现起来可能非常复杂。尤其是当您开始向外扩展时。而且,老实说,如果 1000 条消息对你造成了那么严重的伤害——我的建议可能更适用于你。

您可能希望寻找第三方服务来为您执行此操作,而不是自己实现,例如这个超级酷的网络服务代理Apigee

具体来说,它们的一个功能是 API 速率限制。 (见链接)

【讨论】:

Apigee 看起来很酷。它需要花钱还是有免费计划? (我真的不想为垃圾邮件预防/速率限制付费) 不幸的是它相当昂贵。 哦..我收回...也许有免费版本? apigee.com/about/pricing 哇,每小时 50,000 个 API 请求 太多了! (尤其是免费计划) 试一试...设置相对容易...进行一些小的 DNS 更改,一切就绪。将其与尝试编写自己的软件来跟踪和限制 API 调用进行比较!不用了!

以上是关于如何防止表单在 5 分钟内多次提交?的主要内容,如果未能解决你的问题,请参考以下文章

Rails 5:如何防止来自 jQuery 的多次提交

防止表单多次提交方法之二

Jquery 实现表单提交按钮变灰,防止多次点击提交重复数据

Jquery 实现表单提交按钮变灰,防止多次点击提交重复数据

jQuery防止表单多次提交

如何防止表单重复提交