Blatantly pillaged from this email by Lee Nussbaum to the Rails mailing list. While it deals primarily with security related issues, there are so many goodies in here that aren’t (readily) documented elsewhere.
By default, Rails handles session IDs for you in a fairly quality way, if you use it as supplied. It:
@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.
Blatantly pillaged from this email by Lee Nussbaum to the Rails mailing list. While it deals primarily with security related issues, there are so many goodies in here that aren’t (readily) documented elsewhere.
By default, Rails handles session IDs for you in a fairly quality way, if you use it as supplied. It:
@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.