我在 Rails 生产中收到“无法验证 CSRF 令牌真实性”的消息。我的问题是:
- 它为什么要这样做?
- 我该如何修复它?
这是我的 Heroku 日志(一些值已匿名):
2016-02-13T01:18:54.118956+00:00 heroku[router]: at=info method=POST path="/login" host=[MYURL] request_id=[ID STRING] fwd="FWDIP" dyno=web.1 connect=0ms service=6ms status=422 bytes=1783
2016-02-13T01:18:54.116581+00:00 app[web.1]: Started POST "/login" for [IPADDRESS] at 2016-02-13 01:18:54 +0000
2016-02-13T01:18:54.119372+00:00 app[web.1]: Completed 422 Unprocessable Entity in 1ms
2016-02-13T01:18:54.118587+00:00 app[web.1]: Processing by SessionsController#create as HTML
2016-02-13T01:18:54.118637+00:00 app[web.1]: Parameters: {"utf8"=>"✓", "authenticity_token"=>"[BIGLONGRANDOMTOKENSTRING]", "session"=>{"email"=>"[FRIENDSEMAILADDRESS]", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
2016-02-13T01:18:54.119082+00:00 app[web.1]: Can't verify CSRF token authenticity
2016-02-13T01:18:54.120565+00:00 app[web.1]:
2016-02-13T01:18:54.120567+00:00 app[web.1]: ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
2016-02-13T01:18:54.120569+00:00 app[web.1]: vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.0/lib/action_controller/metal/request_forgery_protection.rb:181:in `handle_unverified_request'
.
.
.etc
我所知道的唯一表现是当我的朋友尝试在他的 iPhone 5 上使用 Safari 登录时。他的用户帐户是大约 6 个月前创建的。我 99% 确信他当时用手机可以正常访问该网站。从那时起,他就没有登录过,我也不知道我对登录/授权代码进行了任何更改。昨天,我让他 6 个月来第一次访问我的网站,现在他收到了 CSRF 错误。
此问题不会发生在任何其他用户帐户(据我所知)或任何其他设备上。事实上,从他的旧 iPhone 4 上登录他的帐户效果很好。
我有相当多的开发经验,但对 Web 开发和 Rails 的一切都是全新的。
这是我所拥有的:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
include SessionsHelper
end
应用布局:
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
我的秘密文件如下所示:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
我在 Heroku 上有一个用于 Secret_key_base 的生产环境变量。
def log_in(user)
session[:user_id] = user.id
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
这是我所做的:
我开始按照以下内容开发我的应用程序Michael Hartl 的 Rails 教程 https://www.railstutorial.org/book/frontmatter直到第 10 章为止。最相关的是第 8 章。具体来说,我的应用程序使用所有安全/cookie/用户身份验证内容,与图特中完全相同。我在我的应用程序中没有做任何花哨的事情......没有 AJAX 或类似的东西。我什至猛拉涡轮链接。
我的项目跨越了过去 18 个月,所以我不能 100% 确定我开始使用哪个版本。我知道它是 4.1.X,也可能是 4.1.6。我也不确定我升级的日期,但在某些时候对我目前正在运行的内容进行了升级; 4.2.0。
我阅读了网上能找到的关于 CSRF + Rails 问题的几乎所有帖子。似乎对于我读过的几乎所有内容,原因和解决方案都与 AJAX 或 Devise 有关,但这两者都不适用于我。 iFrame 问题是网络上的另一个常见来源,但我没有使用它。
我使用了应用程序的密码重置功能,但没有效果。我尝试将 protected_from_forgery 更改为 with: :reset_session。唯一改变的是 Rails 异常页面不再显示。但它不会让他进入任何需要身份验证的页面。这只是让他回到根目录,因为我的路线中有这一行:
get '*path' => redirect('/')
我不想清除他的 cookie/缓存等,因为我有数十个其他现有用户帐户,我不想手动修复它们。
经常建议的解决方案是关闭安全性的一些变体,出于明显的原因我不想这样做。
我已经更改了其他一些内容,但还没有机会测试(因为我无法轻松访问我朋友的 iPhone):
我更改了 session_store.rb 中的应用商店名称:
Rails.application.config.session_store :cookie_store, key: '[NEWNAME]'
运行以下命令:
heroku 运行 rake 资产:clean
heroku 运行 rake 资产:预编译
我即将开始深潜here http://guides.rubyonrails.org/security.html,特别是第 3 节。
感谢您的阅读/考虑。任何提示/想法/建议/指示将不胜感激!