【问题标题】:GET request (no JSON) Can't verify CSRF token authenticity with Devise 3.2.4 on Rails 4.1GET 请求(无 JSON)无法在 Rails 4.1 上使用 Devise 3.2.4 验证 CSRF 令牌的真实性
【发布时间】:2014-07-05 13:25:21
【问题描述】:

突然之间,我无法再登录 heroku 上的应用生产环境。或者,如果我确实进入了,只要我点击一个新链接,我就会被重定向到登录屏幕,如果我再次尝试登录,我就会开始看到错误。

日志如下(这是登录的情况,重定向回登录再登录)。

我的应用程序布局包括 CSRF_meta_tags

!!!
%html
  %head
    %title= full_title(yield(:title))
    = include_gon(:init => true)
    = stylesheet_link_tag "application", media: "all"
    = javascript_include_tag "application"
    = csrf_meta_tags
    = render 'layouts/shim'
    %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
  %body.container-fluid
    #wrapper
      = render 'layouts/navigation'
      = render partial: "shared/flash_messages", flash: flash
      #content
        = yield
        = render 'layouts/footer'
        %br
        - if request.env['HTTP_USER_AGENT'].downcase.match(/android|iphone|ipad/)
        - else 
          = debug(params) if Rails.env.development?
          = debug(@current_user) if Rails.env.development?

我的应用程序控制器是protect_from_forgery 例外。

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

  before_action :authenticate_user!

end

我已经在我的路由文件中为用户设计了。

  devise_for :users, :skip => [:registrations]
    as :user do
      get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
      put 'users/:id' => 'devise/registrations#update', :as => 'user_registration'
    end

日志文件在这里供参考。

Started GET "/users/sign_in" for 58.7.233.232 at 2014-05-16 23:52:48 +0000
Processing by Devise::SessionsController#new as HTML
2014-05-16T23:52:48.995008+00:00 heroku[router]: at=info method=GET path=/assets/application-7d1b02fae40091844b4f616c7ec89e83.js host=slapp.herokuapp.com request_id=8f86c336-0bf2-4419-a07d-0c7ecf79cfb4 fwd="58.7.233.232" dyno=web.2 connect=1ms service=2ms status=304 bytes=249
  Rendered layouts/_shim.html.haml (0.3ms)
  Rendered devise/sessions/new.html.haml within layouts/application (7.9ms)
  Rendered layouts/_navigation.html.haml (1.2ms)
  Rendered shared/_flash_messages.html.haml (0.4ms)
  Rendered layouts/_footer.html.haml (0.4ms)

Completed 200 OK in 18ms (Views: 14.1ms | ActiveRecord: 0.0ms)
2014-05-16T23:52:54.997215+00:00 heroku[router]: at=info method=POST path=/users/sign_in host=slapp.herokuapp.com request_id=6fd107af-4a46-4315-843c-6bbf46827df0 fwd="58.7.233.232" dyno=web.1 connect=7ms service=41ms status=422 bytes=1729

Started POST "/users/sign_in" for 58.7.233.232 at 2014-05-16 23:52:54 +0000
  vendor/bundle/ruby/2.0.0/gems/devise-3.2.4/lib/devise/controllers/helpers.rb:182:in `handle_unverified_request'

Processing by Devise::SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"o5NFnMmQQGcmNxPhzvFYOF+ThrcO1cY1VdZozvQmtOI=", "user"=>{"email"=>"admin@domain.com", "password"=>"[FILTERED]"}, "commit"=>"Login"}

Completed 422 Unprocessable Entity in 9ms

  vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:160:in `block in halting'
  vendor/bundle/ruby/2.0.0/gems/actionpack-4.1.0/lib/action_controller/metal/request_forgery_protection.rb:197:in `verify_authenticity_token'

  vendor/bundle/ruby/2.0.0/gems/activesupport-4.1.0/lib/active_support/callbacks.rb:166:in `call'

Can't verify CSRF token authenticity
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

  vendor/bundle/ruby/2.0.0/gems/actionpack-4.1.0/lib/action_controller/metal/request_forgery_protection.rb:176:in `handle_unverified_request'
  vendor/bundle/ruby/2.0.0/gems/actionpack-4.1.0/lib/action_controller/metal/request_forgery_protection.rb:202:in `handle_unverified_request'

我目前正在通过this similar question 的建议进行故障排除,但到目前为止还没有运气。考虑尝试“protect_from_forgery except::sign_in”,但如果我能找出根本原因,这似乎是一个不必要的妥协。

【问题讨论】:

  • 我在开发环境的一个会话期间查看了多个页面的页面源,并且身份验证令牌始终相同。在生产中,这些页面之间是不同的,我猜这是触发无法验证 CSRF 令牌真实性的原因。
  • 我已经测试了在 heroku 中运行 1 个 dyno 与超过 1 个。一旦我增加到超过 1 个 dyno,我就会开始遇到问题。当进程从 web 1 切换到 web 2 时,将为用户重新创建真实性令牌,然后不再匹配,从而生成错误。似乎没有人能告诉我为什么……或者更可能是我不知道如何正确地问这个问题。

标签: ruby-on-rails heroku devise csrf


【解决方案1】:

我认为 csrf 令牌是在一个 dyno 中生成的,而下一个 http 请求正在命中第二个 dyno,因此 csrf 令牌不匹配。 csrf 令牌需要保存到数据库,以便两个 dyno 共享它。 尝试在提供页面和处理表单时写出 $DYNO。这将显示哪个 dyno 正在处理 csrf 令牌,以及它是同一个 dyno 还是不同的。

【讨论】:

  • 这很有趣。我正在阅读Heroku session affinity($ heroku features:enable http-session-affinity)。您知道启用该功能是否可以解决问题吗?
猜你喜欢
  • 2014-06-16
  • 2012-03-10
  • 2017-07-15
  • 2015-07-24
  • 1970-01-01
  • 2011-11-15
  • 2016-05-12
  • 2012-05-08
  • 2015-12-29
相关资源
最近更新 更多