[Rails] Re: 'Session id' hacking?

Lee Nussbaum wln at scrunch.org
Sun Mar 6 05:53:03 GMT 2005


Neville Burnell <Neville.Burnell at ...> writes:

> But reading the spec indicates that this only ensures the connection is
> using https, so the session can't be hijacked, but can still be hacked
> because the contents of the cookie are plain text [correct?] transmitted
> over https. IE, he can use his https connection and hack his own cookie.
> 
> Imagine a hacker trying to get access to unauthorised details from your
> Rails app. He signs up and gets an account, id=66, and a session id=55.
> The session-id is stored in the cookie in plain text. He edits the
> cookie, changes the session-id to 54, and clicks the 'home' action. Will
> Rails get the hacked session id from his hacked cookie?
> 
> One way to protect against this type of attack is to generate an obscure
> sessionid based on say the ip-address and session creation time, and to
> check the ipaddress of the request against the ipaddress encoded in the
> session.

By default, Rails handles session IDs for you in a fairly quality way, if you
use it as supplied.  It:

	+ creates a cookie using an MD5 hash of data with tolerable amounts of
		entropy, though more would be desirable.
	+ seems to avoid session fixation attacks by taking session IDs only in
		cookies (which are basically site-specific) and not in links (which can
		be used to communicate information cross-site).
	+ makes a store for session state (e.g., @session['user']) available on the
		server, where it is found by session id and not subject to manipulation
		by the user.

As a side observation, one risk to most Rails apps at the moment is the
absence of any hard-to-guess data in forms and URLs, making it particularly
subject to attacks where another site's form is posted by the client's browser
to effect an action not intended by the user.  Including a copy of the Rails
session cookie in generated forms and testing it, on return, against the
actual session cookie should prevent this attack (haven't yet researched how
to do this).  For URL-based actions, you'd have to do something similar with
the URL, which again would have to be for verification only (confirmed against
the actual cookie).

Rails sessions are based on the ruby stdlib 'cgi' module, which notes:

    # The session id is an MD5 hash based upon the time,
    # a random number, and a constant string.  This routine
    # is used internally for automatically generated
    # session ids. 

for the cookie, and then takes the first 64 bits of an additional MD5 hash of
the session cookie to build the local session cache file name, meaning that
any cookies whose hashes collide at that 64-bit value describe the same
session.  Still a huge space, but not as large as the cookie values would
imply.

The entropy in the current session cookie creation data (time of session
including usec, process id, and a pseudorandom number from Ruby's Kernel#rand
-- which, according to the rdoc, is seeded with process start time and process
ID) -- give a tolerable session key, but adding some higher-quality entropy
(from /dev/random or OpenSSL::Random), if available (as it is on most current
OSes), would be quite valuable.  There's not a huge amount of entropy in two
times and a process ID.

As several people have noted already, testing IP addresses creates more
problems than it solves.  Limiting the life of sessions is generally a good
idea, however.  IIRC, if you set a timeout (forgot where/how), Rails/Ruby CGI
sessions do that on the server side simply by associating the times with the
server-side session state, rather than encoding them in the cookie.

Adam Majer writes:
> AFAIK, session ids are generated and given to a user side as a cookie or
> whatever so that we may later "identify" a user and their previous
> authentication by that id. But this is not secure! It doesn't matter if
> we use https or "secure cookies" or some other crap. It doesn't matter.
> As soon as you trust the client to provide you with valid data, you are
> in serious trouble.
>
> Rule #1 - NEVER trust client about authentication
> Rule #2 - Use session ids to *HELP* you identify client's authentication.

You're always going to trust the user to supply you with some form of
indicator of his/her/its identity.  Who else is going to supply it?  The pair
of rules is probably better stated as "Never accept client assertions of 
identity without validating them."

To validate an identity if you're running a stateful server is easy -- just
look for a matching session ID to one originally generated randomly, as Rails'
default use of Ruby cgi does.  For sites that maintain no server-side
per-session state, a piece of server-signed data in the form of an HMAC over
identifying data (username, issue time, and some lifetime indicator)
substitutes well.

 - Lee



More information about the Rails mailing list