Web applications that use sessions are vulnerable to a type of attack called ’session fixation’, where an attacker somehow guesses or otherwise obtains a user’s session unique identifier, and then passes it to the server, impersonating the user. Guessing a session identifier is a nontrivial process, as they are usually based on a random number or other pseudorandom input, such as a client’s IP address.

I got curious, and decided to examine how Rails generates session identifiers, and what I found was, as I could expect, a simple solution.

Session ID Generation in Rails

Rails generates session identifiers using Ruby’s CGI::Session module. There is a method in the file session.rb unsurprisingly called create_new_id. This method is 12 lines long (for comparison, PHP uses 93 lines of C code to generate a session ID ). The relevant Ruby code is:

def create_new_id
require ‘digest/md5′
md5 = Digest::MD5::new
now = Time::now
md5.update(now.to_s)
md5.update(String(now.usec))
md5.update(String(rand(0)))
md5.update(String($$))
md5.update(’foobar’)
@new_session = true
md5.hexdigest
end
private :create_new_id

In a nutshell, what this code will do is get the current time in a string, like “Wed May 17 22:39:01 Eastern Daylight Time 2006″ (on my machine), then get the microseconds of that time, a random number between 0 and 1, the PID of the ruby instance, and the string “foobar”, concatenate them all together, and take the MD5 hash.

How Well Does this Work?

In 1995, Netscape’s implementation of SSL was cracked. Netscape was seeding their random number generator with the time of day, the PID, and the parent PID. It was determined by the two cryptographers that made this discovery that an attacker could fairly easily figure out these values. (Source)

This casts some doubt on Ruby’s usage of the time and PID of the instance, but what about the random number? Well, to generate a random number, Ruby uses a version of the Mersenne Twister algorithm, which is known to be cryptographically insecure, as given the state of the algorithm, one can determine all future states. (Source) (Although this source does mention that a cryptographically secure hash function has been a recommended way of obtaining a useful cryptographic key stream.)

Finally, a beacon of cryptographic security, the string ‘foobar’. No attacker could possibly guess this one. It might be worthwhile to change this.

Conclusion

I am by no means a cryptographer, just an interested party. I have done some basic research into this subject, and these are the results I have found. After reading all of this stuff, I call Ruby’s session ID generation into question; hopefully someone more skilled than I will take some time to examine it.