有没有技术可以防止在无状态web应用程序中重复提交?



我想在现有的java web应用程序(实际上是struts)中实现双重提交预防。架构方面,我们讨论的是2到N个可能的应用服务器(tomcat)和一个单一的数据库服务器(mysql)。各个服务器彼此不认识,也不能交换消息。在应用服务器的前面有一个负载均衡器,它有能力执行会话

所以基本上有两种双重提交预防客户端和服务器端。如果可能的话,我想去服务器端,因为如果人们在浏览器中禁用cookie和/或javascript,所有客户端技术似乎都失败了。

这让我想到了通过数据库锁进行某种类似互斥锁的同步。我认为可以计算用户输入数据的校验和,并将其保存到专用的数据库表中。在每次提交时,应用程序都必须检查是否存在相等的校验和,这将表明给定的提交是重复的。当然,这个表中的校验和必须定期清除。问题是检查数据库中是否已经存在重复的校验和并插入校验和(如果没有)的整个过程几乎是一个临界区。因此,必须事先锁定校验和表,并在section之后再次解锁。

当我想到表锁时,我的死锁瓶颈警钟开始响起。所以我的问题是:有没有更合理的方法来防止在无状态的web应用程序中重复提交?

请注意,struts TokenInterceptor不能在这里应用,因为当cookie被禁用时,它会失败(它依赖于HTTP会话,而HTTP会话没有会话cookie就不存在)。

一个更简单的基于DB的解决方案是这样的。也可以在多个表单中通用。

  • 有一个数据库表,可以用来存储令牌。
  • 当显示一个新表单时-在令牌表中插入一个新行并添加令牌作为表单中的隐藏字段。
  • 当你得到一个表单提交做一个select for update对行与您作为表单的一部分收到的令牌对应。
  • 如果该行仍然存在,那么这是第一次提交。处理
  • 如果行不存在,那么表单已经被处理过了你可以返回一个错误。

防止重复提交的经典技术是分配两个id(都作为HTML表单标签中的"hidden"字段)-一个"session-ID"从登录到注销保持不变…

第二个ID随着每次提交而改变…在服务器端,您只需要跟踪"当前有效的ID"(特定于会话)…如果你收到了"重新提交"(游戏邦注:由"点击快乐用户"或"刷新按钮"或"返回按钮"等),那么这将与当前ID不匹配……这样您就知道:该提交应该被丢弃,并生成一个新的ID并将答案发送回来。有些实现会在每次提交时增加一个ID,这稍微减轻了检查/跟踪部分,但这可能容易受到"猜测"(安全问题)的影响……我喜欢为这种保护生成加密强id…

如果你有一个带有粘性会话的负载均衡环境,那么你只需要跟踪服务器本身的ID(在内存中)…但你当然可以在数据库中存储ID…由于您将它与会话ID存储在一起,因此锁将处于"行级别"(而不是表级别),这应该是可以的。

你描述的方法更进一步,通过检查内容…但我认为内容部分更多的是在"应用逻辑"层面,而不是在"重新提交预防层面",因为它取决于应用逻辑,它是否想再次接受相同的数据…

如果您使用粘性会话,那么使用一些TokenManagement会很好。存在一个DoubleClickFilter,您可以将其添加到您的web.xml中。

由于您有粘性会话,因此不需要跨tomcat解决方案。

最新更新