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

问题描述 投票:8回答:1

我们在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: max-age=0, private, must-revalidate

ruby-on-rails csrf csrf-protection authenticity-token
1个回答
2
投票

已确定并解决。在我们的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

在导轨上,将其添加到您的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

您的应用中的每个操作都应该是全局的吗?这取决于您,但是您将definitely

希望在呈现表单的任何控制器(尤其是登录表单)上或呈现JSON令牌可能过期的任何页面上执行此操作。因此,在现代应用中,简短的答案是肯定的。

如果您明确要保留Rails应用程序响应的缓存,则需要弄清楚如何在嵌入时显式使这些CSRF和JSON令牌到期。

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


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

© www.soinside.com 2019 - 2024. All rights reserved.