Session 正在间歇性重置rails会话

Session 正在间歇性重置rails会话,session,heroku,ruby-on-rails-4,Session,Heroku,Ruby On Rails 4,我知道这个话题已经讨论了很多,但我相信我已经发现了它的一个新变体:我有一个Rails 4应用程序,它是从Rails 3升级而来的,并且有Rails\u ujs和csrf\u meta\u标签设置正确 一旦根url加载到浏览器中,就会有一个javascript触发一个GET和一个PUT,每个都发送到应用程序中各自的控制器API。当这两个API调用被激发时,会话应该在那里有\u csrf\u令牌。大多数时候,这是真的。继续读 问题是,有时(并非总是),我们会看到PUT请求发生一些InvalidAut

我知道这个话题已经讨论了很多,但我相信我已经发现了它的一个新变体:我有一个Rails 4应用程序,它是从Rails 3升级而来的,并且有
Rails\u ujs
csrf\u meta\u标签设置正确

一旦
根url
加载到浏览器中,就会有一个javascript触发一个GET和一个PUT,每个都发送到应用程序中各自的控制器API。当这两个API调用被激发时,会话应该在那里有
\u csrf\u令牌。大多数时候,这是真的。继续读

问题是,有时(并非总是),我们会看到PUT请求发生一些InvalidAuthenticationToken异常。(是的,我在我们的API基础控制器上使用了
protect\u from\u forgery:with=>:exception

通过分析
exception\u通知中的转储
,我可以看到
CSRF\u令牌
在请求头中设置正确,但最有趣的是会话上只有
session\u id
。其他所有东西都不见了,包括
\u csrf\u令牌

记住:这是间歇性的!所以我相信这一定是某种比赛条件

此应用程序托管在Heroku上,运行在Unicorn上。我无法在我当地的环境中重现这个问题。我还阅读了github上的许多Rails代码,试图了解它重置会话的流程,但我找不到答案,因为所有CSRF保护都设置正确,并且问题间歇性地发生

还值得一提的是,我们还没有设置
config.secret\u key\u base
。但由于这个问题是间歇性发生的,我不认为这可能是它的根本原因

此外,我认为值得一提的是,我们有两个控制器层次结构:

(1) 所有“正常”应用程序请求都通过继承自
ApplicationController

(2) 所有API请求都经过从API::BaseController继承的控制器,后者直接从
ActionController::Base
继承

我相信这个控制器方案对每个人来说都是最常见的

GET请求的API端点正在呈现json响应。PUT请求的API端点正在返回
head:ok


好的,如果RubyonRails专家能在这方面提供帮助,我会很高兴的。

您使用的是标准的基于cookie的会话存储吗?我最后一次看到的基于cookie的会话存储肯定会受到竞争条件的影响,特别是在AJAX请求周围——竞争条件是基于cookie的会话存储设计的固有部分,没有真正的方法来修复它

描述一个cookie存储区竞争条件,该条件也涉及真实性令牌,可能与您的类似。他们的解决方案是关闭CSRF保护,不管怎样,对于某些操作,这听起来不是一个很好的解决方案

概述cookie会话存储的竞争条件,并建议使用ActiveRecord或其他服务器端存储作为解决方案。(当我写这篇文章时,这个URL是404'ing,但在谷歌缓存中可用)

从示例中可以看到,会话cookie在每次请求时都会更新,无论会话是否被修改。这取决于最后一次响应返回到客户端的时间,这是将在下一次调用中使用的cookie。例如,如果在我们前面的示例中,如果get_current_result的响应比get_Quike慢,那么我们的cookie将具有正确的数据,下一次调用update_response将正常工作!因此,有时它会起作用,有时并不完全取决于互联网。这种类型的比赛条件是没有乐趣的处理

这意味着在执行多个ajax调用时使用cookie存储会话是不安全的。下次检查时,会话中保存的所有信息可能错误或不存在。那么解决办法是什么呢

更好的解决方案是使用服务器端会话存储,如active record或memcache。这样做可以防止会话数据依赖于客户端cookie。会话数据不再需要在客户机和服务器之间传递,这意味着当同时生成两个ajax时,不再存在潜在的竞争条件

我不能肯定你是否遇到了这个问题,但值得尝试切换到ActiveRecord cookie存储,看看你的问题是否消失了

即使是基于activerecord的会话存储也有,我不确定当前的实现是否是,但至少可以想象它们是可以解决的,而基于cookie的存储中的竞争条件是基本的


实际上,ActiveRecord存储可能会受到与cookie存储类似的竞争条件的约束——如果您有多个应用程序进程(或多线程应用程序服务器)正在运行,那么并发请求处理仍然是可能的,非常类似的竞争条件也可能仍然存在。虽然它可能比cookie存储的竞争条件更为罕见,而且在理论上是可以解决的,尽管可能使用某些特定于域的逻辑,但与cookie存储的竞争条件不同,如果您使用任何异步ajax,竞争条件几乎是不可解的。

要获得更好的格式,请将此作为答案编写,也许这应该是一个评论

我遇到了一个类似的问题,根本原因是我的应用程序名为
当前用户
在执行之前
防止伪造
,这是
当前用户
在Desive中的实现:

      def current_#{mapping}
        @current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
      end
并且设计有一个功能
config.clean\u up\u csrf\u token\u on\u authentication=true

所以问题是,csrf令牌在
当前用户
被调用后被重置。因为它调用了
warden.authenticate
。然后在运行
时保护