A few users are getting a 422 ActionController::InvalidAuthenticityToken error when POSTing a form.
It happens to a minority of users some of the time. If they try their request again later, it often works.
The authenticity token is getting sent along in every case. I'm assuming the client isn't sending the session cookie along with the POST (that would explain why the server can't verify the token). Why would this be?
Finally, the form is submitted via javascript ($('#new_user')[0].submit()), would that somehow prevent the session cookie from being sent?
Disabling the verify_authenticity_token before_filter is unfortunately not an option.
We have run into this scenario with one of our apps. We store our sessions in memcached and if the session is evicted from the cache or the session expires any subsequent post/put/delete raised a 422. We got round this by implementing a before filter 'requires_login?' that checked the session and logout the user out if the session had expired. We then moved the method protect_from_forgery in the application controller to run after requires_login?
E.G
before_filter :requires_login?
protect_from_forgery
Hope this makes sense
Related
I've got a issue where some users that go idle on my site for a period of time receive a CSRF error when submitting post requests. I don't want to disable the security feature in Rails because of its importance, so I was thinking to display a page timeout alert instead. However I cannot find anywhere what the Rails default timeout is for the authenticity_token. Can someone please point me in the right direction?
Thanks in advance.
UPDATE
When I look at cookies for my site Chrome shows that the session cookie expires when the browsing session ends. If that's the case and the reason that I get the CSRF error is due to an expired session, how does it expire if the browser is never closed?
The default behavior is for the CSRF protection to use cookie-based sessions, and for the cookies to expire when the session expires. It sounds like the session is expiring, causing the CSRF error.
I am implementing web app using rails 4.2.0 and ruby 2.2.0 and facing problem that any time request in done new session is set. In that case I cannot save anything to session since it's gone. Also that leads to situation that authenticity token cannot be checked.
For testing purpose forgery protection is disabled in ApplicationController, so that's not reason why session is reset.
class ApplicationController < ActionController::Base
#protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token `
end
I am using active record store to save session, but same happens for cookie store:
MyApp::Application.config.session_store :active_record_store, :key => '_myapp_session', domain: :all, tld_length: 2
Every time request is done new entry to sessions table is inserted with new sessions_id and session cookie in browser points to new session.
Any ideas what could reset session?
This happens only in production environment. In development everything is fine.
Your issue is due to the call to skip_before_action :verify_authenticity_token; if the authenticity token is not verified, Rails will reset the session. You also want to re-enable protect_from_forgery.
I've also seen AJAX requests without an authenticity token to cause the session to reset, again more detail here: http://www.kalzumeus.com/2011/11/17/i-saw-an-extremely-subtle-bug-today-and-i-just-have-to-tell-someone/
Ref: https://stackoverflow.com/a/11943243/449342
I used SAML strategy for devise (https://github.com/apokalipto/devise_saml_authenticatable).
I did some modifications to it and I see that if a user isn't authenticated it goes and authenticate a user and I log that sucess!() called. As result, browser is getting a session cookie.
The browser coming back to my website with this session cookie. However, warden requires to authenticate again (leading to never ending authentication loop) instead of just letting this user through.
My question is: How can I debug it to see why warden calls authentication (vs just letting it through).
I added before_action to ApplicationController and did puts request.env. I see that session cookie is coming. However, I am not sure what should be the next step to check what's going on.
In Rails, using devise, if a CSRF Check fails then the user's current session is cleared, i.e., logs the user out, because the server assumes it's an attack (which is the correct/desired behavior).
But the request, is completed, hence the user record is still created. Hacker can then log in correctly.
How can I stop the method from continuing once devise realises auth_token is incorrect?
Devise doesn't do any checking of the auth token - it's action controller which does this (although it does call handle_unverified_request on your controller so that you can customise behaviour). In rails 4 and higher you can also specify what happens by default when the auth token is invalid:
protect_from_forgery with: :exception
causes an exception to be raised, which would stop the request being processed.
However I am not sure what this buys you though - CSRF is so that an attacker cannot abuse the fact that the user is already logged into your application, but if the attacker has a valid set of credentials then they don't need to do CSRF in the first place.
I have a simple rails app with a single controller. I have a "before filter" for some of the methods of my controller, where I check if the user is logged in by looking at the session object:
#user = User.where(:id => session[:user_id]) if session[:user_id]
In a "login" method of my controller, I do:
session[:user_id] = user.id
Pretty usual stuff. If I access my app from a web browser (Chrome), everything works fine. However, when I use NSURLRequest from my iOS app to access my rails app, the server always creates a new session for each request. It never seems to be able to identify the existing session, even though the request is sending the cookie with the proper session ID in it. In fact, if I look at the "cookies" object in my rails app, I can see it contains the session ID. However, the session object is always empty! Not sure why the server is not able to retrieve the session. I'm using Passenger Phusion. Any suggestions?
If you are POSTing to your login page, and the post does not include a CSRF token matching the token in the session, then Rails will fail the request and invalidate/reset the session as a security precaution.
To fix it, simply read the CSRF token out of the session and include it in your request, or turn off CSRF token checking, you can place skip_before_filter :verify_authenticity_token in your controller to skip the CSRF protection checks. Note that the latter approach does open potential security holes, so including the tokens and checking them is recommended if it is at all viable.