Rails 2.0 cookies (updated)

 

Rails 2.0 will include a new default session storage, the CookieStore (source source). What it does is store the clear text “marshalled” session object in a cookie which will be stored on the client side. Here is an example of a new cookie value:

BAh7BzoMdXNlcl9pZGkKIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpG%250
AbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA–be9c1e802c6cf126c722c680
02ccbd5684a96dd9

Well, it is actually not clear text, but Base64 encoding. So everything you store in the session object can be seen by the client. This is especially bad if you store secrets in the session, because you thought they will be safe there. But it should be safe for saving an id, for example. Update: You can implement an EncryptedCookieStore very easily, so no one can see the information. But again, the password for this encryption has to be strong.
When the cookie travels back from the client to the application, the session data will be “unmarshalled” and made available by means of the session method (e.g. session[:user_id]).

The second part of the cookie (after the –) is a hash (HMAC-SHA1 by default), calculated of the session object along with the secret server side password. On the server side the session value will be checked against this hash, so no one can tamper with it…unless the attacker knows the password (secret) which is in your environment.rb:

  config.action_controller.session = {
    :session_key => ‘_cookies2_session’,
    :secret      => ‘secret-secret’  }

You already know what may happen: the user is able to locally brute-force the secret as he has the clear text and the hash of it (Update: whether or not this will be successful depends on the strength of the secret. A sufficiently long secret is safe.). A weak secret is a short one, or one included in a word list (there are some with 40 million entries). You can try to brute-force your secret with John the Ripper which is very fast (I checked over 105 million passwords in less than half an hour). Update: This means the secret should be a strong password (over 40 characters, no words from dictionaries). The latest Rails release forces you to use a secret with at least 30 characters, and it generates a sufficiently long secret by default.

Corey Benninger presented my book and the most dangerous attack methods for Rails at the OWASP AppSec conference in San Jose. And he wrote a nice Ruby script to crack a Rails cookie (with a too short secret!) here and here.

Update: Replay attacks might be another security issue with client-side cookies. If you store state (is_admin, points, money, amount_to_pay, whatever) in a session, it may be replayed. That means an attacker can resend the state in the cookie and thus possibly reduce a price, get more points or become an admin (if the cookie is from someone else who is an admin). Solutions for this are welcome. In any case, it is not a good idea to save such information in sessions, no matter whether it’s a client- or server-side session store.

There are different cookie stores, depending on your needs. If you use CookieStore, please set a very long secret (over 40 characters, no words from dictionaries), preferably some sort of hash as the Rails generator for new project proposes. Also, keep in mind that an attacker might use the knowledge from the cookie somewhere else in your application.