【问题标题】:How do I prevent double-clicking in ASP.NET MVC without using JavaScript?如何在不使用 JavaScript 的情况下防止在 ASP.NET MVC 中双击?
【发布时间】:2011-10-18 20:01:00
【问题描述】:

是的,其他人have asked similar questions,但是,最终的解决方案是使用 JavaScript。我有这个工作,我的问题变成当用户关闭 JavaScript 时会发生什么?我希望只有高级用户会关闭 JavaScript,从而知道点击一次按钮并知道服务器正在工作。如果他们不这样做,我如何确保该按钮只被点击一次?

我应该注意到这是在付款表格上。

【问题讨论】:

    标签: asp.net-mvc double-click javascript


    【解决方案1】:

    恐怕没有 JavaScript 就无法防止这种情况发生。如果单击导致 POST 请求,那么您可以尝试在服务器端设置为idempotent

    【讨论】:

      【解决方案2】:

      您无法确保按钮只被点击一次,因为您无法控制用户的浏览器。不过,您可以做的是在表单中添加一个隐藏字段,即一个 token,这样如果您看到一个已经看过的令牌,您就可以返回一个已经计算好的回答。

      更新:在付款处理的情况下,它甚至不是一种防止重复提交的技术——它是一种保护您的客户免受欺诈的技术。查看 OWASP 的A5: Cross-Site Request Forgery (CSRF)

      防止 CSRF 需要在每个 HTTP 请求的正文或 URL 中包含不可预测的令牌。此类令牌至少应在每个用户会话中唯一,但也可以在每个请求中唯一。

      1. 首选选项是将唯一标记包含在隐藏字段中。这会导致值在 HTTP 请求的正文中发送,从而避免将其包含在 URL 中,这可能会暴露。

      2. 唯一令牌也可以包含在 URL 本身或 URL 参数中。但是,这样的放置会冒着 URL 暴露给攻击者的风险,从而危及秘密令牌。

      基本上,每次您收到付款表单时,您都希望确保它是对您所显示的表单的合法回复。处理双重提交是免费的,安全性很高——这确实是一种罕见的情况! ;)

      【讨论】:

      • 嗯...对于少数禁用 javascript 的人来说,这听起来真的很复杂。也许通过处理信用卡的 preauth/postauth 方法,我们会更安全地避免双重收费。
      • 确实如此。在大多数情况下,你只是不在乎。但是,当您这样做时,您通常会尝试创建一个层,该层将在您的表单中注入令牌 - 并拦截所有检查令牌的请求,这样其余代码就不需要关心了。
      【解决方案3】:

      当用户关闭 JavaScript 时会发生什么?

      服务器被击中两次,您对此无能为力。

      现在,根据您在服务器上所做的事情,有不同的反应方式。例如,在 RESTful 应用程序中,如果您使用的 POST 动词会修改服务器上的某些状态并且既不安全也不幂等,最终将由底层数据源检测异常并简单地抛出异常,该异常将优雅地报告给用户告诉他他的请求已经提交。

      【讨论】:

        【解决方案4】:

        对于一个简单而小型的 ASP.NET MVC 应用程序,我发现使用 HttpRuntime.Cache 就足够了:

        Function SomeAction() As ActionResult
            Dim cachekey = "uniquecode"
            If HttpRuntime.Cache(cachekey) IsNot Nothing Then
                ' wait until the other request is finished
                Do
                    Threading.Thread.Sleep(1000)
                Loop Until HttpRuntime.Cache(cachekey) Is Nothing
            End If
        
            HttpRuntime.Cache.Add(
                cachekey, "", Nothing,
                DateTime.Now.AddMinutes(5),
                Cache.NoSlidingExpiration, CacheItemPriority.Low, Nothing)
        
            Try
        
                ' do stuff
        
            Finally
                HttpRuntime.Cache.Remove(cachekey)
            End Try
        End Function
        

        cachekey 对于您认为是双重的请求必须相同,并且必须与所有其他请求不同。如果您检查缓存键是否已经在缓存中,请告诉正在处理请求的线程等待(或抛出错误)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-31
          • 2014-03-26
          • 2012-04-24
          • 2011-09-11
          • 2015-12-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多