devise_token_auth icon indicating copy to clipboard operation
devise_token_auth copied to clipboard

CSRF protect_from_forgery with: :null_session is skipped

Open antulik opened this issue 4 years ago • 1 comments

  • Version: 1.2.0
  • Environmental Info:
    • Gems: devise (4.8.0), rails (6.1.4.1)
    • enable_standard_devise_support = true
    • protect_from_forgery with: :null_session

We have controller that is already using rails session for the authentication. We want to add token auth in addition. They will run in parallel to allow transition.

Adding include DeviseTokenAuth::Concerns::SetUserByToken to the controller works well, but CSRF is broken.

After debugging it, this is why it happens:

  • Request gets to the controller and we execute before actions
  • We set user locale. This will get current_user, but since it's a first time we get user, we authenticate.
    • When set_user_by_token is called, it sets @resource instance variable.
  • CSRF before action is executed
    • protect_from_forgery with: :null_session
    • When CSRF is invalid, handle_unverified_request is called
      • https://github.com/heartcombo/devise/blob/8593801130f2df94a50863b5db535c272b00efe1/lib/devise/controllers/helpers.rb#L254-L258
    • The session is reset and all good.
  • Controller action is executed
    • Controller requests current_user, which is nil because it was cleared in the previous step
    • set_user_by_token is called again to get user
    • Because we enable_standard_devise_support = true we check devise. https://github.com/lynndylanhurley/devise_token_auth/blob/6d7780ee0b9750687e7e2871b9a1c6368f2085a9/app/controllers/devise_token_auth/concerns/set_user_by_token.rb#L58
    • Devise auth is nil (correct and expected)
    • Then we get to this line https://github.com/lynndylanhurley/devise_token_auth/blob/6d7780ee0b9750687e7e2871b9a1c6368f2085a9/app/controllers/devise_token_auth/concerns/set_user_by_token.rb#L69
    • Because @resource was previously set and wasn't cleared by invalid CSRF, we authenticate user and ignore invalid CSRF token

Expected: Authentication should fail after session was reset

Actual: User is authenticated with invalid CSRF token.

antulik avatar Nov 19 '21 04:11 antulik

A temporary patch

# config/initializers/devise_token_auth.rb

# https://github.com/lynndylanhurley/devise_token_auth/issues/1514
module DeviseTokenAuthCSRFPatch
  def handle_unverified_request(*)
    super.tap do
      @resource = nil
    end
  end
end

DeviseTokenAuth::Concerns::SetUserByToken.include DeviseTokenAuthCSRFPatch

antulik avatar Nov 21 '21 22:11 antulik