Rails4 ActionController :: InvalidAuthenticityToken错误

我有Rails4应用程序在生产中运行,我的访问者偶尔运行ActionController :: InvalidAuthenticityToken错误,我无法重现。 我从各种表格收到每日2-4次通知,背后没有明确的逻辑。 我收到的报告显示,表单提交的authenticity_token与会话中保存的不同。 这怎么可能? 我设法自己遇到问题几次,但是无法重现,表单的所有突然的authenticity_token都与会话中存储的不同,并且出现了InvalidAuthenticityToken。
任何想法从哪里开始寻找?

例:

Request: ------------------------------- * URL : https://domain/signin * HTTP Method: POST * IP address : 113.96.xx.xx * Parameters : {"utf8"=>"✓", "authenticity_token"=>"MOh9JDE1AZ0CbIw/M33vfhjRShwzI6oqMhi8lk+n7OE=", "email"=>"xxxx@xxx", "password"=>"[FILTERED]", "commit"=>"Sign In", "controller"=>"clients", "action"=>"signin", "locale"=>"en"} ------------------------------- Session: ------------------------------- * session id: [FILTERED] * data: {"_csrf_token"=>"QazCSVGeZlxEh83XTM+f5PkC/zopwCF96yV4duRats0="} 

更新:想要添加我通过两个负载均衡的AWS EC2实例服务页面,并在Redis ElastiCache实例中存储会话

Rails生成的任何表单(即使用form_for等,而不是将

放在模板中)都会在必要时将反CSRF令牌添加为隐藏字段。 如果您自己编写表单并且没有包含CSRF隐藏输入,那么Rails依赖于CSRF元标记和JavaScript来实现工作。 因此,如果您编写自己的表单并且未包含隐藏字段,并且如果客户端的JavaScript因任何原因无效,则可能会出现此错误。 因为“客户端的JavaScript无论出于何种原因无效”子句是一个难以检测和调试的子句,所以我实际上故意删除了我网站上的CSRF元标记。 这样,如果我忘记包含隐藏的输入,它将为每个人打破(快速失败),我会立即发现它,我可以解决它。 我建议你也这样做。

话虽如此,我建议您查看这些“访问者”的访问日志。 你觉得奇怪吗?

  • 他们在提交之前是否立即访问包含该表单的页面? 如果没有,也许他们是机器人或实际的,实际的CSRF尝试(这是检查的,不是吗?:))。
  • 他们是否在一个EC2上加载表格并最终提交给另一个? 如果是这样,你可以关闭一个EC2,看看错误是否消失?
  • 他们以某种方式失去了他们的会话? 这可能是你的问题或他们的问题。

由于rails使用JavaScript将authenticity_token附加到rails表单,因此我会双重检查您是否没有基于导致此heisenbug的动态内容的运行时JS错误。 如果JS错误我们要破坏整个application.js文件,那么您的表单将无效。 这可能吗?

要回答我自己的问题,如果有人遇到同样的问题,似乎从标题中删除csrf_meta_tag为我们解决了问题。 我不知道为什么。 可能是负责设置auth_token的rails javascript在某种程度上干扰了我们的javascript并导致了问题,但我的直觉是它不得不在服务器或客户端上使用缓存。 无论如何,在删除csrf_meta_tag后,我们似乎摆脱了这个问题。 只需确保您为所有表单使用form_tag。

登录时发生这种情况会让我怀疑您的退出时可能出现问题,从而为退出并立即重新登机的用户触发问题。

注销通常会破坏当前用户会话并将其替换为新会话,从而使CSRF标记无效。 通常这不是问题,因为用户被重定向到包含新CSRF标记的另一个页面。

我可以看到这是一个问题,如果

  • logout会导致可能在浏览器或代理中缓存的页面
  • 注销是通过AJAX完成的,在极少数情况下,无法在成功时做正确的事情,无法更新CSRF标记

我遇到了同样的麻烦。 服务器:nginx +乘客

nginx.conf:

 http { ... expires 90d; ... server { server_name domain1.com ... } server { server_name domain2.com ... } server { server_name domain_3_with_rails.com ... } } 

教学中的问题“到期90d”; 浏览器本地缓存的页面,包含表单和authenticity_token。

解决方案:添加"expires 0d;" 对于rails域:

nginx.conf:

 http { ... expires 90d; ... server { server_name domain1.com ... } server { server_name domain2.com ... } server { server_name domain_3_with_rails.com expires 0d; ... } } 

之后,请务必重启Nginx。

对于那些拥有apache的人:apache肯定有一个类似的语句“expires”为nginx

我现在有同样的问题。 我一直在四处寻找,我注意到如果我关闭cookie(阻止域可以使用cookie),每次我做POST都会遇到ActionController :: InvalidAuthenticityToken。

因此用户已启用JS但不允许使用Cookie。

Rails中的反CSRF令牌的AFAIK作为会话cookie服务器端发送,然后由于无法设置cookie而失败。