Are Ruby Session ID’s Secure?

The question of the security of cookie-based session storage in Rails has pretty much been settled it seems to me. Out of the box, Rails uses cookie-based session storage. When you generate a new Rails app you get a nice new 128 character long (numbers and lowercase letters) secret set in config.action_controller.session[:secret] in your Rails::Initializer. That secret is used to sign and validate cookies for your application. Now the cookie data isn’t secret mind you, but it is tamper-proof. Good.

Now what if you don’t use cookie-based session storage at all? Well, just because you aren’t using cookie-based session storage doesn’t mean you aren’t using cookies. If your application has sessions at all, be they memcached ones or ActiveRecord ones, it is probably using cookies. It’s using cookies to store the session id so that when a request arrives, that id can be mapped to the corresponding session storage.

“So what” you say. “Well” I say… isn’t it cool that Rails generates that big random secret for you when you use cookie-based session storage? When we are not using cookie-based session storage, and that secret is not generated, don’t you wonder what secret is being used to secure your session id’s? You see, a session id must be hard to guess lest bad people gain access to your site. Usually when you want to make something hard to guess, you start with a secret and mix that with something that changes a lot and hash the whole shebang. So I went in search of this other secret.

What I found was that Rails calls CGI::Session#create_new_id to generate new session id’s. That routine uses no secrete per se. It hashes (MD5) a combination of:

  1. the current date and time (expressed as a human-readable string)
  2. the microseconds elapsed since the last second (expressed as a human-readable string)
  3. a pseudo-random number greater than zero and less than one (from Kernel#rand)
  4. the current process id number
  5. the string ‘foobar’

Notice there is no secret keying material there. “But what about the Kernel#rand call Bill!” I hear you saying. If you go have a look at Kernel#rand and Kernel#srand you’ll see that if rand is called before srand is called with a number parameter then the random number will be generated from a combination of:

  1. the current time
  2. the process id number

So the security of these session ids hinges on the secrecy of current time (on the server running Ruby) and the process id. Given that the system time is returned in HTTP headers and process id’s are often in the hundreds or thousands, it’s only really the microseconds that are hard to guess here, from a statistical standpoint. Others have expressed similar concerns.

If you’re worried about this two suggestions come to mind:

  • time out sessions on the server so that an attacker has to guess faster
  • monkey-patch CGI::Session#create_new_id to hash its result with a great big old 128 character secret

Updated: October 15, 2008 expanded analysis of Kernel#rand and Kernel#srand and updated suggestions.

This entry was posted in Ruby, Ruby on Rails, security. Bookmark the permalink.

3 Responses to Are Ruby Session ID’s Secure?

  1. Chris Heald says:

    I think the key here is that Ruby’s rand *seeds* itself from known values. If there is any single call to rand at any time not coincident with an HTTP header that the end user is made privvy to, then the values returned from rand are effectively unpredictable.

  2. Bill says:

    Chris, the first version of this post was misleading. It implied that the first call to rand set the seed material for subsequent calls. In fact it is only the srand call that does that.

    My new reading is that if srand is never called, then rand will use current time and process id each time it is called. Essentially, srand is only used in testing situations (where you want to take system time and process id out of the equation and make your pseudorandom sequence predictable). In other words—not our situation.

  3. Greg says:

    Netscape has a similar problem 12 years ago in their original implementation of SSL!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s