我在Heroku中有一个Rails 5应用程序,它使用基于Michael Hartl的Ruby on Rails教程中的逻辑的会话控制器进行登录/注销。从Rails 3开始,我已经做了几年类似的逻辑。我的应用程序在localhost,生产状态下使用Passenger在我的服务器和Heroku上工作。正在执行相同的代码。几天前,当我尝试在服务器上登录应用程序的生产版本时,我开始遇到以下错误。但是,我仍然可以在localhost / development和Heroku上登录我的应用程序。
I, [2017-04-22T20:15:50.242323 #65501] INFO -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] Started POST "/sessions" for 127.0.0.1 at 2017-04-22 20:15:50 -0500
I, [2017-04-22T20:15:50.243524 #65501] INFO -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] Processing by SessionsController#create as HTML
I, [2017-04-22T20:15:50.243945 #65501] INFO -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] Parameters: {"utf8"=>"✓", "authenticity_token"=>"RsEqEfiDw82E2YI17SVkkUcxhiqtUw75nC1i9GJmIYZlwjg6o0mXiHehCHP627iTOjyQoPA+mrmi+Bh99BxICQ==", "session"=>{"email_user"=>"pamela", "password"=>"[FILTERED]"}, "commit"=>"Login"}
W, [2017-04-22T20:15:50.245161 #65501] WARN -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] Can't verify CSRF token authenticity.
I, [2017-04-22T20:15:50.246050 #65501] INFO -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] Completed 422 Unprocessable Entity in 2ms (ActiveRecord: 0.0ms)
F, [2017-04-22T20:15:50.248110 #65501] FATAL -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c]
F, [2017-04-22T20:15:50.248546 #65501] FATAL -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
F, [2017-04-22T20:15:50.248894 #65501] FATAL -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c]
F, [2017-04-22T20:15:50.249263 #65501] FATAL -- : [40a379f9-27c2-4923-a9ce-f310f96dbc4c] actionpack (5.0.2) lib/action_controller/metal/request_forgery_protection.rb:195:in `handle_unverified_request'
[40a379f9-27c2-4923-a9ce-f310f96dbc4c] actionpack (5.0.2) lib/action_controller/metal/request_forgery_protection.rb:223:in `handle_unverified_request'
[40a379f9-27c2-4923-a9ce-f310f96dbc4c] actionpack (5.0.2) lib/action_controller/metal/request_forgery_protection.rb:218:in `verify_authenticity_token'
application_controller
protect_from_forgery with: :exception
include SessionsHelper
在我能够成功登录的同一台计算机上从localhost登录:
Started POST "/sessions" for ::1 at 2017-04-22 22:26:23 -0500
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"zhkoMofyRdPcwQ7v2GOYltlRv2PJM8duzbuxJsa5dAy0je/yj1CRedQM/H1Zku2ukQbbG7YF6OZd4ootV0qolA==", "session"=>{"email_user"=>"myuserid", "password"=>"[FILTERED]"}, "remember_me"=>"1", "commit"=>"Login"}
[1m[36mUser Load (74.2ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."email" = $1 LIMIT $2[0m [["email", "myuserid"], ["LIMIT", 1]]
[1m[36mUser Load (0.8ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."username" = $1 LIMIT $2[0m [["username", "myuserid"], ["LIMIT", 1]]
[1m[35m (0.2ms)[0m [1m[35mBEGIN[0m
[1m[35mSQL (22.6ms)[0m [1m[33mUPDATE "users" SET "remember_token" = $1, "updated_at" = $2 WHERE "users"."id" = $3[0m [["remember_token", "75f5152d815e24e6ce7709cc93f34265ad9161be"], ["updated_at", 2017-04-23 03:26:23 UTC], ["id", 3]]
[1m[35m (26.4ms)[0m [1m[35mCOMMIT[0m
Redirected to http://localhost:3000/
Completed 302 Found in 229ms (ActiveRecord: 124.5ms)
Started GET "/" for ::1 at 2017-04-22 22:26:23 -0500
Processing by PagesController#home as HTML
[1m[36mUser Load (7.4ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."remember_token" = $1 LIMIT $2[0m [["remember_token", "75f5152d815e24e6ce7709cc93f34265ad9161be"], ["LIMIT", 1]]
Rendering pages/home.html.erb within layouts/application
Rendered pages/home.html.erb within layouts/application (1.1ms)
Rendered layouts/_meta_data.erb (2.3ms)
Rendered layouts/_shim.html.erb (0.4ms)
Rendered layouts/_header.html.erb (1.1ms)
Rendered layouts/_systemmessage.html.erb (0.5ms)
Rendered layouts/_footer.html.erb (1.0ms)
Completed 200 OK in 270ms (Views: 236.8ms | ActiveRecord: 7.4ms)
我有搜索解决方案,并且几乎所有人都说关闭这个我不想做的事情,特别是考虑到这是一个数据库维护应用程序。我在代码的三次执行之间可以看到的唯一区别是我的表中的remember_token的值,因为每个版本使用不同的数据库。我尝试将数据库上的remember_token字段设置为null但我仍然得到错误。我没有改变任何与登录/注销过程相关的内容,所以我真的很困惑。我将克隆Heroku中的内容并重试。
这是我在Rails软件开发近六年来第一次看到这个错误。我意识到我很可能有攻击,但我不知道如何调试此错误。相同的代码适用于Heroku和localhost。
更新:我查看了服务器上生产应用程序的页面源代码。这是我尝试登录并收到错误之前的标题。使用我的localhost版本和Heroku版本,登录后会显示以下两个语句。
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="JoPFlDzY0SYSpOSq0dXgafSICgZ9qXJz/x4tX31owZPh3cu7fNR553iGPn5c+RnZVOuxiEolnoOin0Rkoay4Ag==" />
更新:尝试覆盖rails/actionpack/lib/action_controller/metal/request_forgery_protection.rb
中第195行引发的类InvalidAuthenticityToken。目前这个班级没有任何陈述。由于我没有看到任何相关说明或者甚至可能有这样的说明,所以在这一点上进行了大量猜测。
require 'action_controller/metal/request_forgery_protection'
class XxxLogger < ActionPack::ActionController::RequestForgeryProtection
source_root File.join(File.dirname(ActionPack::ActionController::RequestForgeryProtection.instance_method(:handle_unverified_request).source_location.first), "templates")
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
logger.warn "Can't verify CSRF token authenticity
end
end
答案 0 :(得分:0)
有2个令牌需要验证,form token
,csrf token
。任何一个令牌失败,都会抛出InvalidAuthenticityToken
例外。
在生产部署目录中,运行bundle show rails
,找到确切的rails
目录,然后将日志添加到相关的rails代码中,找到详细原因。
以这种方式添加日志,logger.warn "Can't verify CSRF token authenticity."
,这就是rails输出日志的方式。
在actionpack/lib/action_controller/metal/request_forgery_protection.rb
文件中,找到any_authenticity_token_valid?
首先失败的原因。
并检查此问题https://github.com/rails/rails/issues/24257#issuecomment-212203983,更改为users_path
,而不是users_url
。
并照顾好这一点,
For Rails 5, note that protect_from_forgery is no longer prepended to the before_action chain, so if you have set authenticate_user before protect_from_forgery, your request will result in "Can't verify CSRF token authenticity." To resolve this, either change the order in which you call them, or use protect_from_forgery prepend: true.