Conditionally bypassing rails protect_from_forgery
Posted on November 28th, 2010 in Programming, Rails, Ruby, Web Development | No Comments »
I'm currently writing a neat little application using Rails 3.0. It serves up web requests and provides a nice RESTful end point for me to rig up some fancy calls to via a JavaScript UI.
To compliment this web application, I have written a primitive NodeJS substrate to manage communications with mobile devices. Though this layer, mobile devices can invoke actions on the web application. This works fairly well, except when request_from_forgery gets in my way. I needed to get around this restriction, but I did not want to disable CSRF completely on the web application. In a nutshell, I wanted to check the CSRF tokens if the user is coming from any non-trusted source and ignore the tokens when coming from a trusted source.
Since the NodeJS is in my sphere of trust and has already authenticated any users that it is communicating with it, I created a non-standard header to communicate a signed identity to my web application. The web application verifies this identity and then invokes the method being called on behalf of that identity. However, since I supply no CSRF token the request failed. Ideally, if the identity sent in the header is valid (and signed by the NodeJS application) I want to also ignore the CSRF token. However, I want the CSRF token to be verified for any other request. Rails provides a mechanism to ignore the verification token per controller or method, but I want a much deeper level of control (per request).
Here's what I did. If the authentication token is valid, I modify the request to place it in the forgery whitelisted category. This means it will not verify any tokens and the request will proceed as if it does not require CSRF validation. To do this I redefined the forgery_whitelist? method on the request object. It more or less looked like this:
if custom_header.is_valid? def request.forgery_whitelisted?; true; end end