CSRF 令牌与 session 中的内容不匹配 (Rails 4.1)

CSRF tokens to not match what is in session (Rails 4.1)

我们在 Rails 4.1 应用程序中发现了一个不幸的 browser-based CSRF 令牌真实性问题。我们将它张贴在这里是为了询问社区是否其他人也看到了它。

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

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

我们看到的异常只是 ActionController::InvalidAuthenticityToken 正常登录我们的网站。仔细检查表格发送的authenticity_token和session的_csrf_token(我们正在使用 active_record_store 作为我们的 session_store 设置),它们只是不匹配 。直接检查,我只能得出结论,它们是完全不同的标记,但我不知道为什么。

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

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

我们的Cache-controlheaders设置如下:

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

这已被识别并修复。在我们的 Rails 4.1 应用程序中未设置缓存控制 headers,导致

的默认 headers
Cache-Control: max-age=0, private, must-revalidate

这个 header 还不足以强制浏览器不缓存。因此,登录表单和 JSON 令牌被客户端浏览器(尤其是移动客户端)缓存,并返回已过期的 session_ids。

修复:

设置cache-control和编译指示header,如此

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

Pragma: no-cache

IN 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

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

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

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


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