html – 为什么Rails给我“无法验证CSRF令牌真实性”错误?
我在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提供了一个生产环境var. 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 这就是我所做的: 我的项目已经持续了18个月,所以我不是100%肯定我开始使用哪个版本.我知道它是4.1.X,可能是4.1.6.我也不确定我升级的日期,但在某些时候对我现在正在运行的日期做了什么; 4.2.0. 我已经阅读了几篇关于CSRF Rails问题的网上发现的帖子.似乎几乎所有我读过的内容,原因和解决方案都与AJAX或Devise有关,这些都不适用于我. iFrame问题是网络上的另一个常见来源,我也没有使用. 我用我的应用程序的密码重置功能无济于事.我尝试将protect_from_forgery更改为:: reset_session.唯一改变的是Rails异常页面不再显示.但它不会让他去任何需要身份验证的页面.它只是让他回到root,因为我在我的路线中有这条线: get '*path' => redirect('/') 我不想清除他的cookie /缓存等,因为我有许多其他现有的用户帐户,我不想手动修复. 经常建议的解决方案是关闭安全性的一些变体,出于显而易见的原因我不想这样做. 我已经改变了一些其他的东西,但还没有机会测试(因为我没有轻松访问我朋友的iPhone): 我更改了session_store.rb中的appstore名称: Rails.application.config.session_store :cookie_store,key: '[NEWNAME]' 执行以下命令: 我即将开始深入研究here,尤其是第3部分. 感谢您阅读/考虑.任何提示/想法/建议/指针将不胜感激! 解决方法
原来
this gentleman与我有完全相同的问题,并能够创建一个适合我的repro案例.如果我理解正确,Safari正在缓存页面但是会话.这导致authenticity_token值在我的rails params中看起来是合法的,但是在验证令牌时protect_from_forgery失败,因为会话已被破解.
然后解决方案有两个:关闭缓存并处理CSRF异常.即使关闭缓存,您仍然需要处理异常,因为某些浏览器(例如Safari)不尊重无缓存设置.在这种情况下,出现了CSRF问题,因此也需要处理这个问题. 我的解决方法是通过消除所有cookie和会话数据来处理CSRF异常,刷新“oops”消息并将它们重定向到登录页面.重定向将拉下一个新的身份验证令牌,该令牌将在执行登录帖子时进行验证.这个想法来自here:
rescue_from ActionController::InvalidAuthenticityToken do |exception| sign_out_user # Example method that will destroy the user cookies end
cookies.permanent正是我??所使用的.所以我实现了上面这样的提示: class ApplicationController < ActionController::Base include SessionsHelper protect_from_forgery with: :exception before_filter :set_cache_headers rescue_from ActionController::InvalidAuthenticityToken do |exception| cookies.delete(:user_id) cookies.delete(:remember_token) session.delete(:user_id) @current_user = nil flash[:danger] = "Oops,you got logged out. If this keeps happening please contact us. Thank you!" redirect_to login_path end 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"] = "Fri,01 Jan 1990 00:00:00 GMT" end end 顺便说一句,在实现修复并验证它在dev中工作后,我朋友的手机仍然无法登录,尽管行为不同.经过调查,我发现他的iPhone 5 Safari设置中“所有cookie被阻止”.这导致了其他奇怪的行为,这使得很难理清哪个问题导致了什么.当我意识到我无法使用他的手机登录任何在线账户(例如雅虎邮件等)时,提示就出现了.进入他的Safari设置并允许cookie解决问题,现在一切都在他的手机(以及我所知道的其他地方)上运行良好. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |