dav*_*idh 8 html security ruby-on-rails erb 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
Run Code Online (Sandbox Code Playgroud)
我所知道的唯一表现就是当我的朋友试图在他的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
Run Code Online (Sandbox Code Playgroud)
应用布局:
<!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>
Run Code Online (Sandbox Code Playgroud)
我的秘密文件看起来像这样:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
Run Code Online (Sandbox Code Playgroud)
我在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
Run Code Online (Sandbox Code Playgroud)
这就是我所做的:
我开始开发我的应用程序,遵循迈克尔·哈特尔的Rails教程中的所有内容到达/通过第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('/')
Run Code Online (Sandbox Code Playgroud)
我不想清除他的cookie /缓存等,因为我有许多其他现有的用户帐户,我不想手动修复.
经常建议的解决方案是关闭安全性的一些变体,出于显而易见的原因我不想这样做.
我已经改变了一些其他的东西,但还没有机会测试(因为我没有轻松访问我朋友的iPhone):
我更改了session_store.rb中的appstore名称:
Rails.application.config.session_store :cookie_store, key: '[NEWNAME]'
Run Code Online (Sandbox Code Playgroud)
执行以下命令:
heroku run rake assets:clean
heroku run rake assets:precompile
我即将在这里深入探讨,特别是第3节.
感谢您阅读/考虑.任何提示/想法/建议/指针将不胜感激!
事实证明,这位先生遇到了与我完全相同的问题,并且能够创建一个适合我的复制案例。如果我理解正确的话,Safari 会缓存页面,但会破坏会话。这导致在我的 Rails 参数中,authenticity_token 值看起来合法,但在验证令牌时,protect_from_forgery 失败,因为会话已被破坏。
解决方案有两个:关闭缓存和处理 CSRF 异常。即使关闭缓存,您仍然需要处理异常,因为某些浏览器(例如 Safari)不尊重无缓存设置。在这种情况下,就会出现 CSRF 问题,因此也需要处理该问题。
我的解决方法是通过杀死所有 cookie 和会话数据来处理 CSRF 异常,闪烁“oops”消息并将它们重定向到登录页面。重定向将拉下一个新的身份验证令牌,该令牌将在执行登录帖子时进行验证。这个想法来自这里:
使用持久性cookie来存储用户信息是很常见的,例如cookies.permanent。在这种情况下,cookie 将不会被清除,开箱即用的 CSRF 保护也不会生效。如果您使用与会话不同的 cookie 存储来存储此信息,则必须自行处理如何处理它:
rescue_from ActionController::InvalidAuthenticityToken do |exception|
sign_out_user # Example method that will destroy the user cookies
end
Run Code Online (Sandbox Code Playgroud)
上述方法可以放置在 ApplicationController 中,并且当 CSRF 令牌不存在或在非 GET 请求上不正确时将被调用。
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
Run Code Online (Sandbox Code Playgroud)
顺便说一句,在实施修复并验证其在开发中有效后,我朋友的手机仍然无法登录,尽管行为有所不同。经过调查,我发现他的 iPhone 5 Safari 设置中“阻止了所有 cookie”。这导致了其他奇怪的行为,使得很难弄清楚哪个问题导致了什么。当我意识到我无法使用他的手机登录任何在线帐户(例如雅虎邮箱等)时,我收到了消息。进入他的 Safari 设置并允许 cookie 解决了问题,现在他的手机(以及我所知道的其他任何地方)一切都运行良好。
| 归档时间: |
|
| 查看次数: |
4186 次 |
| 最近记录: |