Crontab: A rails story ft. CSRF

Once upon a time there was a beautiful and gentle rails application called Rails. She was much adored by her creators and her compatriots. Even though she was queried about a million times she was always very pleasant to work with and was always humble in responding to others’ requests. Her responses were always graceful. You would think everything was fine with this beautiful creature of ethereal proportions, but that would mean you are wrong. Not all things were equally mesmerised by her. Crontab was one of those fiends who always wanted to curl or wget her. But these requests were always protected by her security expert protect_from_forgery.

Well we all have gone through this phase!

Crontab was not an easy man to be rejected and just like any other immature male his ego was hurt. He went and asked the creators for a boon. The ability to make POST requests to the Rails. The creator granted this wish and Rails had to comply. But there was always 422 from Rails. Rails did not allow CSRF requests and returned 422. This was her natural behaviour. She could always do a skip_before_filter :verify_authenticity_token on the controller on which she wanted to enable the CSRF to happen, but since she was a person with a lot of admirers and requests this was not an option. What was to be done ?

This is probably a time for us to take a break from the story and understand some basic terms which makes this story quite compelling and interesting.


CSRF vulnerabilities occur when a website allows an authenticated user to perform a sensitive action but does not verify that the user herself is invoking that action.The key to understanding CSRF attacks is to recognize that websites typically don’t verify that a request came from an authorized user. Instead they verify only that the request came from the browser of an authorized user. Because browsers run code sent by multiple sites, there is a danger that one site will (unbeknownst to the user) send a request to a second site, and the second site will mistakenly think that the user authorized the request. If a user visits an attacker’s website, the attacker can force the user’s browser to send a request to a page that performs a sensitive action on behalf of the user. The target website sees a request coming from an authenticated user and happily performs some action, whether it was invoked by the user or not.

Above is the definition given by Bill Zeller in his Freedom To Tinker blog. This pretty much makes clear that these kind of attacks are quite common and need to be prevented. Proactively, Rails makes sure that these kind of attacks are not allowed. But how does crontab cause this issue?

When a large scale application is running in a browser session and is accepting requests from browser, it should be prevented from these kind of attacks. When a crontab makes a wget or curl request with non idempotent verbs(POST is a primary example) what the application thinks is that the requests have originated from malicious sources and prevents it from being made. How can rails disable this?

A normal solution to this would be to add skip_before_filter :verify_authenticity_token to the controller which is serving the crontab requests. This would make sure that the controller need not verify the authenticity token. Okay definitions again. What is authenticity token ?

Controller actions are protected from Cross-Site Request Forgery (CSRF) attacks by including a token in the rendered HTML for your application. This token is stored as a random string in the session, to which an attacker does not have access. When a request reaches your application, Rails verifies the received token with the token in the session. All requests are checked except GET requests as these should be idempotent. This token is called authenticity token.

Are there any other solution. Seems there are. Enter null_session.

Null session

A null session is something that is returned when the site which makes the requests do not possess the authenticity token. Rails application essentially creates a null session which is an instance of NullSessionHash. This essentially ensure that one does not have access to another sessions data and sensitive actions on that session. Well Rails is brilliant in many respects and this is one of those instances. This would cater the request and would also make sure that the requests are not overreaching. Well when it concerns a lady these kind of preventions are necessary.

Reset Session

Its also possible to reset the session when a CSRF request comes in. We can possibly reset the session by removing all the data associated with the session and creating a new session specifically for the request being made.

Now coming back to the story…

Armed with these knowledge, it was possible to handle crontab as well as CSRF in one shot. Can anybody guess what approach was taken ? I can give you a hint. Never an ace where a deuce would suffice.

Not this ace