【问题标题】:optimistic concurrency with timestamp and typed dataset in asp.netasp.net 中带有时间戳和类型化数据集的乐观并发
【发布时间】:2011-09-13 20:11:40
【问题描述】:

我正在使用 c# 和 asp.net 为我的网站创建一个论坛系统,我正在使用类型化数据集和 UI 我正在使用 mvp 模式来访问数据。在我的数据库中,我存储了已添加到数据集中的过程。问题是数据集不允许我选择“使用乐观并发”复选框,所以我必须自己实现乐观并发。我已经在我的表中添加了一个时间戳列,现在我在为每个用户保存这个值时遇到了问题!那么什么样的状态管理方法在保存时间戳值时是安全且成本更低的呢??

我认为最好使用 session 来存储值,但如果用户的计数增加,我会遇到内存资源问题,但是我可以将 session 设置为使用 sql server 而不是内存,但我不知道有多少那会更慢,所以我无法决定。

感谢任何帮助!

Edit1: 是的。我想跟踪行的最后修改以查看它是否与用户拥有的匹配。但我不知道在哪里保存用户的时间戳值。

【问题讨论】:

  • 时间戳/行版本有什么问题?
  • 嗨,吉姆,除非您解释“现在我在为每个用户保存此值时遇到问题”的意思,否则我认为人们无法帮助您。你能更好地解释一下你的问题吗?

标签: c# asp.net sql-server optimistic-concurrency


【解决方案1】:

如果您由于某种原因不能使用时间戳/行版本,因为它是一个论坛类型的应用程序,我猜您会跟踪帖子创建/修改的日期/时间?如果是这样,这将很容易检查。

更新

SQL Server 模式

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 应用程序时更改该值。

让我们分析一下我们所知道的:

  • Microsoft 不建议手动递增它以防止在同一个表中重复相同的 rowversion。
  • 按表插入/更新顺序递增,而不是按记录递增。即记录 A 可能有版本 1 记录 B 可能有版本 2。对记录 A 的下一次更新将使其 3 而不是 2。请参阅http://msdn.microsoft.com/en-us/library/ms182776.aspx

基于此,我们将编写应用程序以使用 rowversion,以便我们使用 rowversion 来确定记录是否在当前请求的更新之间发生了变化。我们将始终让数据库在内部增加 rowversion。因此,存储过程将接受该值以进行比较,但不会在表/视图中插入或更新它。

那么,如果有人试图操纵它,rowversion 可能会发生什么情况。

  1. 客户端提供的 rowversion 小于 DB 的 rowversion。
  2. 客户端提供的 rowversion 等于 DB 的 rowversion。
  3. 客户端提供的 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 可能不是一个选项,因为它违背了目的。

结论

那么论坛网络应用程序是否安全?我们仍然需要验证输入,但如果 rowversion 与预期不同,我们有办法解决这个问题。

作为最后的最后手段,我们还可以对 rowversion 进行编码或加密,以防止序列被轻易猜到。

所以在我看来是的,但这最终是你的决定。

【讨论】:

  • 我应该在哪里保存用户版本的日期时间/时间戳??因为如果用户想要更新一行,我想将该值传递给数据库。
  • @jim 检索帖子进行编辑时,将当前版本放入网络表单或您正在使用的任何内容中。提交后,将其与数据库中的当前版本进行比较。如果不同,则将其反馈给用户或其他逻辑。如果您然后刷新编辑或发布从数据库返回新的行版本。不要尝试将 rowversion 保存到数据库,让它自行更新。
  • 这正是我的问题!将 rowversion 放在网络表单中是不安全的。正如我在我的问题中所说,会话状态在使用 InProc 或 StateServer 模式时太重了,那么如果我将会话状态设置为使用 SQLServer 模式是否足够快?
  • @jim 为什么将它放在网络表单中不安全?您将它放在网络表单中,因此您不必保留它的状态,它将被发回给您。它仅用于比较目的,这就是您不想将其写入数据库的原因。您不将 rowversion 写入数据库的原因是因为它是由 SQL 管理的,虽然在某些情况下您可以覆盖,但 MS 建议您不要这样做。这可能有助于msdn.microsoft.com/en-us/library/ms182776.aspx
  • 因为它可以被篡改。最好说您可以将其用作实现 DOS(拒绝服务)攻击的错误。那么sql server模式呢?速度够快吗?
猜你喜欢
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-26
  • 2021-06-25
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
相关资源
最近更新 更多