Choosing a session ID algorithm for a client-server relationship
The basic concept of a session identifier is that it is a short-lived secret name for the session, a dynamic relationship which is under the control of the server (i.e. under the control of your code). It is up to you to decide when sessions starts and stop. The two security characteristics of a successful session identifier generation algorithm are:
- No two distinct sessions shall have the same identifier, with overwhelming probability.
- It should not be computationally feasible to "hit" a session identifier when trying random ones, with non-negligible probability.
These two properties are achieved with a random session ID of at least, say, 16 bytes (32 characters with hexadecimal representation), provided that the generator is a cryptographically strong PRNG (/dev/urandom
on Unix-like systems, CryptGenRandom()
on Windows/Win32, RNGCryptoServiceProvider
on .NET...). Since you also store the session ID in a database server side, you could check for duplicates, and indeed your database will probably do it for you (you will want this ID to be an index key), but that's still time wasted because the probability is very low. Consider that every time you get out of your house, you are betting on the idea that you will not get struck by lightning. Getting killed by lightning has probability about 3*10-10 per day (really). That's a life threatening risk, your own life, to be precise. And yet you dismiss that risk, without ever thinking about it. What sense does it make, then, to worry about session ID collisions which are millions of times less probable, and would not kill anybody if they occurred ?
There is little point in throwing an extra hash function in the thing. Properly applied randomness will already give you all the uniqueness you need. Added complexity can only result in added weaknesses.
Cryptographic functions are relevant in a scenario where you not only want to have session, but you also want to avoid any server-based storage cost; say, you have no database on the server. This kind of state offloading requires a MAC and possibly encryption (see this answer for some details).
Session IDs need to be cryptographic strength random, and unique. If an attacker can guess a legitimate session ID, he may impersonate that user.
Option 1 is your best bet, as long as you use a proper CSPRNG, and not something like rand()
from a standard library. Using something like option 2 isn't as safe, since usernames and times are easily guessed or brute-forced.
Take a look at how PHP's session ID generator code works, and you'll see that a hash function is used to combine the IP address of the client, the current time (seconds and microseconds) and some values from PHP's Linear Congruence Generator (LGC) RNG as a baseline. If an OS-specific random source is available, further entropy is mixed into the ID from that function. This gives a reasonable security margin if no strong entropy source is available, but provides strong security if one is.