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

时间:2017-07-26 14:22:05

标签: ruby-on-rails csrf csrf-protection authenticity-token

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

请注意,大多数错误报告工具(如Honeybadger)会自动禁止 ActionController :: InvalidAuthenticityToken ,因此您通常不会在错误报告工具中看到问题,除非您不在你看待它的方式。

这就是问题,这不是一个发展问题 - 这是一个尚未被诊断出来的生产问题。

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

这不是一个简单的新手开发者问题,请不要回答有关如何将CSRF令牌从客户端传递到服务器或如何在我的控制器上跳过伪造保护的基本答案。我对这两个答案中的任何一个的任何人都没有兴趣:你不知道自己在谈论什么,而且你不了解问题的深度和复杂性。我只对那些拥有高流量网站的人们感兴趣,他们可以确认这种情况发生在非无关紧要的访问者身上(奇怪的是,这似乎比其他浏览器更频繁地影响某些浏览器。)

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

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

我们的Cache-control标头设置如下:

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

1 个答案:

答案 0 :(得分:2)

已经确定并修复了这个问题。我们的Rails 4.1应用程序中未设置缓存控制标头,导致

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

此标头不足以强制浏览器不缓存。因此,登录表单和JSON令牌由客户端浏览器缓存 - 特别是移动客户端 - 并返回已过期的session_ids。

修复:

设置cache-control和pragma 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

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

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

请注意,症状表现在主要是移动客户端的微妙发生级别。