9

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

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

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

当我想到桌锁时,我的僵局瓶颈警钟开始响起。所以我的问题是:有没有更明智的方法来防止无状态 Web 应用程序中的重复提交?

请注意,strutsTokenInterceptor不能在这里应用,因为当 cookie 被禁用时它会失败(它依赖于 HTTP 会话,如果没有会话 cookie,它根本不存在)。

4

3 回答 3

7

一个更简单的基于数据库的解决方案将是这样的。这也可以在多种形式中通用。

  • 有一个可用于存储令牌的数据库表。
  • 显示新表单时 - 在令牌表中插入新行并将令牌添加为表单中的隐藏字段。
  • 当您收到表单提交时,请在与您作为表单一部分收到的令牌对应的行上选择更新。
  • 如果该行仍然存在,那么这是第一次提交。处理提交并删除该行。
  • 如果该行不存在,则该表单已被处理 - 您可以返回错误。
于 2011-09-19T16:27:14.173 回答
1

防止重复提交的经典技术是分配两个 ID(都作为 HTML 表单标签中的“隐藏”字段) - 一个“会话 ID”,从登录到注销保持不变......

每次提交时第二个 ID 都会更改...服务器端您只需要跟踪“当前有效 ID”(特定于会话)...如果您收到“重新提交”(通过 click-happy-user或“刷新按钮”或“后退按钮”或...)然后与当前 ID 不匹配...这样您就知道:应该丢弃此提交并生成新 ID 并将其发回与答案。一些实现使用一个在每次提交时都会修改的 ID,这可以稍微简化检查/kepp 跟踪部分,但可能容易受到“猜测”(安全问题)的影响……我喜欢为这种保护生成加密强 ID。 ..

如果您有一个具有粘性会话的负载平衡环境,那么您只需要跟踪服务器本身(内存中)上的 ID...但是您当然可以将 ID 存储在数据库中...因为您存储它与会话 ID 一起,锁将位于“行级别”(不是表级别),这应该没问题。

您描述的方式通过检查内容更进一步......但是我在“应用程序逻辑”级别上看到的内容部分比在“重新提交防止级别”上更多,因为它取决于应用程序逻辑是否想要再次接受相同的数据...

于 2011-09-19T16:21:59.403 回答
0

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

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

于 2011-09-19T16:27:25.037 回答