如果由于某种原因您不能使用时间戳/行版本,因为它是一个论坛类型的应用程序,我猜您会跟踪帖子创建/修改的日期/时间?如果是这样,这将是一件容易检查的事情。
更新
SQL 服务器模式
SQL Server 模式的用例通常是一个 Web 服务器场,以便 ASP.NET 会话状态在多个服务器上持续存在。这使它稍微健壮一些,因为如果一个 Web 服务器变得不可用,只要另一个可用,会话就可以正常继续。SQL Server 模式不如本地快,除非资源受到严重竞争,因为我们查询的是数据库而不是同一服务器的内存中(进程外),甚至是同一进程中(进程内)。
MVC 模式和会话状态
如果您在应用程序中使用 WebFormViewEngine,则可以使用状态,但是 MVC 模式的主要租户是无状态的。
如何跟踪无状态的行版本/时间戳
要以无状态方式跟踪 rowversion,我们需要将其返回给客户端,以便在回调控制器操作时为我们提供它。
<%= Html.HiddenFor(Model.VersionId) %>
这将导致生成的 HTML 表单中的隐藏字段。
<input type="hidden" name="VersionId">1</input>
安全吗?
将其临时存储在客户端上是否安全,完全知道也许有人可以更改值作为对您的 Web 应用程序的攻击的一部分。
让我们分析一下我们所知道的:
基于此,我们将编写应用程序以使用 rowversion,以便我们使用 rowversion 来确定记录是否在当前请求的更新之间发生了变化。我们将始终让数据库在内部增加 rowversion。因此,存储过程将接受该值以进行比较,但不会在表/视图中插入或更新它。
那么如果有人试图操纵它,rowversion 可能会发生什么情况。
- 客户端提供的 rowversion 小于 DB 的 rowversion。
- 客户端提供的 rowversion 等于 DB 的 rowversion。
- 客户端提供的 rowversion 大于 DB 的 rowversion。
现在让我们分解一下。
因此,如果客户端 rowversion 小于 DB,这意味着什么?
客户在编辑数据时使用了旧的数据副本,因为自从他们上次从数据库中读取数据后,它已经发生了变化。为了解决这个问题,我们可以:
A. 给他们一个错误,重新加载数据并让他们重新提交他们的更改。
B. 将他们的更改合并到当前副本中,并在重新提交之前要求确认。
C. 覆盖数据库中的现有副本。好吧,我们可以这样做,但是由于我们实现了一个并发模型来同时处理多个更改,因此它可能不是最合适的。这给我们留下了A和B。
另一个选项是客户端将 rowversion 的值更改为小于实际的 DB 值。在这种情况下,即使他们确实改变了 rowversion 的值,这有关系吗?我建议不要这样做,并且应该像与另一个用户同时发生更改一样处理它。再次返回选项 A 和 B。
那么如果客户端rowversion等于DB,那是什么意思呢?
客户正在编辑他们期望的版本并点击提交按钮。为了解决这个问题,我们可以:
A. 接受他们的改变并继续。
B. 拒绝更改并提供反馈信息。我们不太可能想要这样做,因为它的重点是将数据输入数据库。
另一种选择是客户端将 rowversion 的值更改为我们期望的完全正确的版本,或者很可能根本没有修改它,因为我们告诉他们我们期望什么 rowversion,就像我们对所有提交所做的那样。但是如果他们确实改变了 rowversion 并且同时有客户端发布了他们的更新,这是最后一次提交的更新。
我们可以像之前 A 或 B 一样处理这种情况。不幸的是,我们无法知道他们实际上修改了 rowversion,因为它符合预期。但是,我们已经授予他们更新记录的权限。如果他们不应该更新记录,那么他们不应该有这样做的权限。
也就是说,我们仍将验证所有输入的完整性并在将其写入数据库之前对其进行清理。
如果这样做不好,那么我们需要在我们的应用程序中实施内容版本控制或批准流程,以便在我们更新每条记录或允许回滚到以前的版本之前给予我们控制权。
那么如果客户端rowversion大于DB,这是什么意思呢?
好吧,选项与 rowversion 小于 DB 完全相同。这是没有预料到的,所以要么 A 要么 B。同样,C 可能不是一个选项,因为它违背了目的。
结论
那么论坛 Web 应用程序是否安全?我们仍然需要验证输入,但如果 rowversion 与预期不同,我们有解决此问题的方法。
作为最后的最后手段,我们还可以对 rowversion 进行编码或加密,以防止序列被轻易猜到。
所以在我看来是的,但这最终是你的决定。