我想在现有的Java Web应用程序中实现双提交预防(实际上是struts)。在架构方面,我们讨论的是2到N个可能的应用服务器(tomcat)和一个单一的数据库服务器(mysql)。各个服务器彼此不了解,也无法交换消息。在应用程序服务器前面有一个负载均衡器,可以进行粘性会话。
所以基本上有两种双提交预防客户端和服务器端。如果可能的话,我想进入服务器端,因为如果人们在浏览器中禁用cookie和/或javascript,所有客户端技术似乎都会失败。
这让我想到通过数据库锁进行某种类似互斥的同步。我认为可以计算用户输入数据的校验和并将其持久保存到专用数据库表。在每次提交时,应用程序必须检查是否存在相等的校验和,这表明给定的提交是重复的。当然,必须定期清除此表中的校验和。问题是检查数据库中是否存在重复校验和以及如果没有校验和,则插入校验和的整个过程几乎都是关键部分。因此,必须事先锁定校验和表,并在该部分之后再次解锁。
当我想到表锁时,我的死锁和瓶颈警报响铃开始响起。所以我的问题是:是否有更好的方法来阻止无状态Web应用程序中的双重提交?
请注意,struts TokenInterceptor
无法在此处应用,因为当禁用Cookie时它会失败(它依赖于HTTP会话,如果没有会话cookie,它就不会出现)。
答案 0 :(得分:6)
更简单的基于数据库的解决方案就是这样的。这也可以在多种形式中变得通用。
答案 1 :(得分:1)
防止双重提交的经典技术是分配两个ID(在HTML Form标签中都是“隐藏”字段) - 一个“会话ID”,从登录到退出保持不变...
第二个ID随每次提交而变化...服务器端您只需要跟踪“当前有效ID”(特定于会话)...如果您获得“重新提交”(通过点击 - 快乐用户或“刷新按钮”或“后退按钮”或...)然后与当前ID不匹配...这样你知道:应该丢弃此提交并生成新的ID然后送回答案。 一些实现使用在每次提交时都会使用的ID,这会使check / kepp跟踪部分变得容易,但可能容易“猜测”(安全问题)... 我喜欢为这种保护生成加密强ID ...
如果你有一个带有粘性会话的负载均衡环境,那么你只需要跟踪服务器本身的ID(内存中)......但是你当然可以将ID存储在数据库中...你将它与会话ID一起存储,锁定将在“行级别”(不是表级),这应该没问题。
您所描述的方式更进一步检查内容...但我看到内容部分更多地在“应用程序逻辑”级别而不是“重新提交预防级别”,因为它取决于应用程序逻辑是否它想再次接受相同的数据......
答案 2 :(得分:0)
如果您使用粘性会话,那么您可以使用一些TokenManagement。您可以将DoubleClickFilter
添加到web.xml
。
由于您有粘性会话,因此不需要Cross-Tomcat-Solution。