【发布时间】:2011-11-20 09:32:28
【问题描述】:
我想在现有的 java web 应用程序(实际上是 struts)中实现双重提交预防。架构方面,我们谈论的是 2 到 N 个可能的应用程序服务器(tomcat)和一个单一的数据库服务器(mysql)。各个服务器彼此不认识,无法交换消息。在应用服务器前面有一个负载均衡器,它能够执行粘性会话。
所以基本上有两种防止双重提交的客户端和服务器端。如果可能的话,我想去服务器端,因为如果人们在浏览器中禁用 cookie 和/或 javascript,所有客户端技术似乎都会失败。
这让我想到了通过数据库锁进行某种类似互斥锁的同步。我认为可以计算用户输入数据的校验和并将其保存到专用的数据库表中。在每次提交时,应用程序必须检查是否存在相等的校验和,这表明给定的提交是重复的。当然,必须定期清除此表中的校验和。问题是检查数据库中是否已经存在重复校验和并在没有校验和时插入校验和的整个过程几乎是一个关键部分。因此校验和表必须预先锁定并在节后再次解锁。
当我想到桌子锁时,我的死锁和瓶颈警钟开始响起。所以我的问题是:有没有更明智的方法来防止无状态 Web 应用程序中的重复提交?
请注意,struts TokenInterceptor 不能在这里应用,因为当 cookie 被禁用时它会惨遭失败(它依赖于 HTTP 会话,如果没有会话 cookie,它根本不存在)。
【问题讨论】:
-
你知道POST-REDIRECT-GET pattern吗?对你的情况没有用吗?
-
防止无状态双重提交不是不可能吗?不是双重提交令牌状态,存储在哪里?一个相同的事务可能不会被双重提交,它可能只是一个相同的事务。所以检查你的数据层可能也行不通。
-
您是否预计会有很多没有 JavaScript和 没有 cookie 的用户?您确定投资回报率值得付出努力吗?在任何情况下,您几乎都将自己置于依赖数据库哈希的角落,因为您不能保证第二次点击将由同一台服务器处理,也不能保证应用程序状态会足够快地复制。您还需要非常快地使这些哈希条目过期,因为这可能是合法的重新提交。也许保留一个大的内存映射,而不是使用几个实现(或内存数据库)中的任何一个?
-
@brandizzi 这种模式很有用,但在我的情况下服务器对提交的回复可能需要一些时间并且用户通常会再次提交相同的请求。
-
@DaveNewton 我不知道为什么,但似乎有很多用户没有启用 cookie 和/或 JavaScript。由于这个原因,之前依赖 HTTP 会话属性的简单解决方案确实失败了。
标签: java web-applications struts stateless double-submit-prevention