9

我们在 Rails 4.1 应用程序中看到了一个不幸且可能基于浏览器的 CSRF 令牌真实性问题。我们在这里发布它是为了询问社区其他人是否也看到它。

请注意,大多数错误报告工具(如 Honeybadger)会自动抑制ActionController::InvalidAuthenticityToken,因此您通常不会在错误报告工具中看到问题,除非您特意去查看它。

这就是问题所在,这不是一个开发问题——它是一个尚未诊断的生产问题。

我们看到的异常只是正常登录我们网站时的 ActionController::InvalidAuthenticityToken。在仔细检查表单发送的authentity_token和会话的_csrf_token(我们使用active_record_store 作为我们的session_store 设置)后,它们只是不匹配。经过直接检查,我只能得出结论,它们是完全不同的令牌,但我不知道为什么。

我们广泛地看到了这个问题,大概是我们高流量网站的 1-2%。我只在生产中看到它,我无法在开发中重现它。

我在 IE 11 和 Edge 浏览器上看到它最多(你会注意到 Rails 4.1 是在 IE 11 和 Edge 之前发布的),但也在 Android 上的 Chrome 和偶尔的移动 Safari 上看到。

我们的缓存控制标头设置如下:

Cache-Control: max-age=0, private, must-revalidate

4

1 回答 1

3

这已被识别并修复。我们的 Rails 4.1 应用程序中没有设置缓存控制头,导致默认头

Cache-Control: max-age=0, private, must-revalidate

此标头不够强大,无法强制浏览器不缓存。因此,登录表单和 JSON 令牌被客户端浏览器缓存——尤其是移动客户端——并返回过期的 session_id。

修理:

设置缓存控制和编译指示头,如

Cache-Control:no-cache, no-store, max-age=0, must-revalidate

Pragma: no-cache

在 rails 中,将其添加到您的 application_controller.rb :

before_action :set_cache_headers
def set_cache_headers
  response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
  response.headers["Pragma"] = "no-cache"
  response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
end

它应该对您应用程序中的每个操作都是全局的吗?这取决于您,但您肯定希望在呈现表单的任何控制器上执行此操作,尤其是登录表单,或者呈现可能过期的 JSON 令牌的任何页面。所以在现代应用程序中,简短的回答是肯定的。

如果您明确希望缓存您的 Rails 应用程序响应,您需要弄清楚如果嵌入这些 CSRF 和 JSON 令牌,如何显式过期。

请注意,症状在大多数移动客户端上以细微的发生级别表现出来。


我在这里的一篇博文中对此进行了探讨,请访问我的博客并考虑在那里发表评论进行讨论:https ://blog.jasonfleetwoodboldt.com/2017/09/03/the-great-rails-cache-lie/

于 2017-08-14T21:37:45.273 回答