html – 为什么Rails给我“无法验证CSRF令牌真实性”错误?

前端之家收集整理的这篇文章主要介绍了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

这就是我所做的:
我开始开发我的应用程序,跟随Michael Hartl’s Rails Tutorial中的所有内容到达/通过第10章的信件.最相关的是第8章.具体来说,我的应用程序使用所有安全/ cookie /用户身份验证的东西,就像在tut中一样.我的应用程序中没有任何奇特的东西…没有AJAX或类似的东西.我甚至猛拉了涡轮.

我的项目已经持续了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]'

执行以下命令:
heroku运行rake资产:干净
heroku运行rake资产:预编译

我即将开始深入研究here,尤其是第3部分.

感谢您阅读/考虑.任何提示/想法/建议/指针将不胜感激!

解决方法

原来 @L_502_2@与我有完全相同的问题,并能够创建一个适合我的repro案例.如果我理解正确,Safari正在缓存页面但是会话.这导致authenticity_token值在我的rails params中看起来是合法的,但是在验证令牌时protect_from_forgery失败,因为会话已被破解.

然后解决方案有两个:关闭缓存并处理CSRF异常.即使关闭缓存,您仍然需要处理异常,因为某些浏览器(例如Safari)不尊重无缓存设置.在这种情况下,出现了CSRF问题,因此也需要处理这个问题.

我的解决方法是通过消除所有cookie和会话数据来处理CSRF异常,刷新“oops”消息并将它们重定向登录页面.重定向将拉下一个新的身份验证令牌,该令牌将在执行登录帖子时进行验证.这个想法来自here

It is common to use persistent cookies to store user information,with cookies.permanent for example. In this case,the cookies will not be cleared and the out of the Box CSRF protection will not be effective. If you are using a different cookie store than the session for this information,you must handle what to do with it yourself:

rescue_from ActionController::InvalidAuthenticityToken do |exception|
  sign_out_user # Example method that will destroy the user cookies
end

The above method can be placed in the ApplicationController and will be called when a CSRF token is not present or is incorrect on a non-GET request.

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解决问题,现在一切都在他的手机(以及我所知道的其他地方)上运行良好.

猜你在找的HTML相关文章