CSRF and rails

Written by Walter Schreppers

Today I noticed some dangerous behaviour in a new rails app I generated. The csrf meta tag failing only generates a warning in rails 3.2.3 but the post data still is submitted and saved in the database!

After looking around a little not many seem to mind this (it basically happened when the removed the exception and cleared the session data instead). But for me this is critical as it stops protecting for instance an anonymous blogpost from being done with xml http requests. Basically now a user is silently logged out (and if you have authentication in place which only allows logged in users to post it does indeed prevent anonymous posts still) but I believe the throwing of an exception if the csrf is missing is a more secure way of rejecting invalid posts.

Long story short you can get back to a similar old behaviour (the data will not be saved and just bounced if csrf fails) by overriding the handle_unverified_request method in your application controller:

def handle_unverified_request
logger.info("Bouncing request because CSRF token failed here!")
#response.code = 404
#will get our 500 error
raise UnauthorizedError
end




Anyway hope this helps someone else who notices you can still post the data when omitting a csrf tag. Just copy the above method into your application controller and you're back in secure land ;)

Make sure you send the csrf token in all ajax posts:

// Make sure that every Ajax request sends the CSRF token
function CSRFProtection(xhr) {
var token = $('meta[name="csrf-token"]').attr('content');
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
}
if ('ajaxPrefilter' in $) $.ajaxPrefilter(function(options, originalOptions, xhr) { CSRFProtection(xhr); });
else $(document).ajaxSend(function(e, xhr) { CSRFProtection(xhr); });


Now if you want to explicitly skip this for certain actions in a controller (for instance an external process or api call that can't use csrf tags):

skip_before_filter :verify_authenticity_token, :only => :create

Back to archive