Search code examples
csrfrailstutorial.org

Can't get the user session to be reset when CSRF token authenticity is not verified


After a couple of weeks playing with rails app and completing the rails tutorial, I wanted to learn about some common web attack in web applications.

I managed to perform a CSRF attack type using the below chunk of code in a .html file.

<form action="http://localhost:3000/users/2" method="post">
  <input type="hidden" name="_method" value="delete">
  <div>
    <input type="submit" value="Delete">
  </div>
</form>

Being logged in as an admin, I run the attack against my own code that was based on same session mechanism as Railtutorial and I succeed deleting the user where it should have been stopped as the authenticity token was missing.

The default behavior should be a session reset thus preventing the user being deleted outside of the web application.

I can see the 'Can't verify CSRF token authenticity' in the log, but the session is not reset.

Overriding the handle_unverified_request method, that should by default reset the session, with

def handle_unverified_request
  raise(ActionController::InvalidAuthenticityToken)
end

the error get raised properly.

Running the attack on Railstutorial git code from railstutorial/sample_app_2nd_ed freshly install, I faced the exact same issue: the session is not reset as it should be. That mean the tutorial app is vulnerable to that kind of attack.

I dig a bit deeper into the code (http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-reset_session) but cannot figure out why in the context Railstutorial it doesn't seem to work.

Could anyone verify, If the tutiral is indeed vulnerable to CSRF attck? if yes would the solution be to rewrite the handle_unverified_request to do proper signout in that case? Finally why is it not working as it should be?

Thanks for your help.


Solution

  • I figure out how to force the signout of the user if the CSRF token can't be verify.

    It seems related to the fact that we empty the session but not the remember token of the cookie.

    Override handle_unverified_request in your application (so that all controller benefit from it) and add the sign_out method to clean the remember token.

    class ApplicationController < ActionController::Base
      protect_from_forgery
      include SessionsHelper
    
      def handle_unverified_request
        sign_out
        super
      end
    end