Hongli
Hongli

Reputation: 18944

Writing an encrypted cookie session store for Rails; is my approach secure?

By default, Ruby on Rails stores session data in cookies. This has many advantages, such as the lack of need to setup any persistence layers on the server side. However, the session data is not encrypted, and the Rails app that I'm writing puts potentially sensitive data in the session. I'd like to avoid storing session data server-side if possible, and the only existing encrypted cookie store implementation for Rails seems to be abandoned, so I'm writing my own encrypted cookie store.

The Rails cookie session store works as follows:

  1. It serializes the session data into a byte string.
  2. The serialized data is converted to base64.
  3. The base64 data is appended by an HMAC. Rails requires the HMAC secret key to be at least 30 bytes; by default Rails generates a 128 byte random string as secret key, obtained from /dev/urandom. The default hashing algorithm used for the HMAC is SHA-1.
  4. The base64 data + HMAC is sent to the HTTP client as a cookie.
  5. When the client performs a request, Rails first checks whether HMAC verification succeeds. If not then it will silently discard the session data in the cookie, as if the user didn't sent any session data at all. This also means that if the administrator changes the HMAC secret key, then all old sessions are automatically invalidated.
  6. The base64 data is de-base64'ed and unmarshalled into Ruby data structures.

The encrypted cookie session store that I'm writing subclasses the normal cookie store class. It works as follows:

The reason why I HMAC before encrypting (instead of HMAC after encrypting) is because I want to be able to detect changes to the encryption key or the IV. I want the software to automatically invalidate old sessions if the encryption key or IV is changed. If I HMAC after encrypting then HMAC verification will pass if I change the encryption key or IV, which is undesirable.

Is my approach secure? If not, then what's lacking?

A few notes:

Upvotes: 4

Views: 2989

Answers (3)

Inshallah
Inshallah

Reputation: 4814

As oggy already pointed out, you should generate a unique IV and add it to each cookie. To generate a unique IV, /dev/urandom is not good enough since it is possible that it will generate the same IV for two separate cookies.

Although I'm not an expert I think one valid method to generate a unique IV is to encrypt a counter, that is incremented for each cookie, with a key that is not the same as the key used to encrypt the cookie data with.


Added much later:

There is another reason, which I have only thought of later, why it may not be such a good idea to use /dev/(u)random exclusively for IVs in the scenario that the OP outlined. In the manpage random(4), it says that users should be economical in their use of /dev/urandom, or they might degrade the quality of randomness for other users of the device. Since the quantity of data read is proportional to client-requests, you have to assume that a large amount of randomness will eventually be read in the OP's scenario.

Key-generators will probably be reading from /dev/random, which blocks, but other more legitimate users of these devices (more interested in randomness) will have their randomness degraded. Well, it's not so good to block key generators either.

So, since the OP doesn't want to depend on 3rd party libraries so much, he can reuse the AES encryption functions, using them in counter mode as I've outlined above (also in the wikipedia article under the heading Designs based on cryptographic primitives.

Upvotes: 0

caf
caf

Reputation: 239171

OpenSSL doesn't need a seperate CTR mode. To implement CTR mode, you keep a block-sized counter and encrypt that counter in ECB mode. You then XOR the encrypted counter with the plaintext block and increment the counter. Decryption is the same process (so the cookie must contain its initial counter value). You must never re-use the same counter value with the same key, so ensure that the counter is only ever reset if the key is changed.

Upvotes: 1

oggy
oggy

Reputation: 3571

I'm not sure I'm reading you 100% correctly, but if I am, you seem to be missing the point of using an IV. You seem to plan to have a secret IV which you will use for every cookie.

There's no need for IVs to be secret. Furthermore, you should never reuse the same IV with the same key.

Other than that, I don't see any significant flaws. Which doesn't imply that they don't exist.

Upvotes: 1

Related Questions