25

I am developing an application which has a client-server relationship, and I am having trouble deciding on the algorithm by which the session identifier is determined. My goal is to restrict imposters from acquiring other users' private data.


I'm considering two options:

Option 1: Generate a random 32-character hex string, store it in a database, and pass it from the server to the client upon successful client login. The client then stores this identifier and uses it in any future request to the server, which would cross-check it with the stored identifier.

Option 2: Create a hash from a combination of the session's start time and the client's login username and/or hashed password and use it for all future requests to the server. The session hash would be stored in a database upon the first request, and cross-checked for any future request from the client.

Other info: Multiple clients can be connected from the same IP simultaneously, and no two clients should have the same session identifier.


Question: Which of these options is a better approach, with regards to my concerns (below) about each?

My concern over the first option is that the identifier is completely random and therefore could be replicated by chance (although it's a 1 in a 3.4 * 1038 chance), and used to "steal" one user's (who would also need to be using the client at the time) private data.

My concern over the second option is that it has a security flaw, namely that if a user's hashed password is intercepted somehow, the entire session hash could be duped and the user's private data could be stolen.

Thanks for any and all input.

3
  • 1
    Many proposed session handlers are posted to security.se. I suggest doing some research into this topic before coming up with your own system.
    – rook
    Commented Dec 2, 2012 at 21:01
  • Most of the proposed session handlers I've seen are all website-browser relationships, which aren't entirely applicable to a client-server relationship. Is there a more concise tag I should be searching by?
    – FThompson
    Commented Dec 2, 2012 at 21:22
  • 1
    In the generic sense there is no difference. You still can't trust the client, and many of the same attack patterns still exist.
    – rook
    Commented Dec 2, 2012 at 22:22

3 Answers 3

31

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:

  1. No two distinct sessions shall have the same identifier, with overwhelming probability.
  2. 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).

3
  • What if someone intercepts this random SEssion ID(Token) and forwards later with the hope to access the server?
    – user68920
    Commented Feb 23, 2015 at 11:55
  • 1
    Good point. While the random number as session id is the most compact information to send along with all transactions, you should also store the client ip address and browser information on the server side. When a client sends a request, locate the associated session info on the server and check also that the ip and browser type match. You should also add a limit in time of the session token since the last access and a hard limit to force a relogin.
    – chmike
    Commented Jun 9, 2015 at 6:18
  • The only point I disagree with is "There is little point in throwing an extra hash function in the thing." The client can store the random 16 bytes as is, but the database should store it hashed so that if the database is leaked, the attacker will not be able to impersonate a user.
    – No_name
    Commented Jan 24, 2021 at 19:28
6

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.

5
  • Thanks, I'll be going with option 1 then. If I could mark two answers as accepted, I would, but I feel like Thomas's answer better addressed my concerns. Great answer regardless; +1.
    – FThompson
    Commented Dec 2, 2012 at 23:33
  • Glad it was helpful. I agree that Thomas gave a better answer, too. There's a reason he's known as our resident cryptographer!
    – Polynomial
    Commented Dec 2, 2012 at 23:41
  • I would point out that PHPs built in session generator isn't all that great, at least not until the RNG is replaced by a cryptographically secure one.
    – ewanm89
    Commented Dec 3, 2012 at 0:56
  • @ewanm89 Thanks for the point out; I'm already using Java's CSPRNG (SecureRandom) for my 128-bit unique session identifiers.
    – FThompson
    Commented Dec 3, 2012 at 1:35
  • @ewanm89 If you read through the code, you'll see that it is cryptographically secure. The baseline is a weak combination of an LCG and various time / IP values, but if an OS-specific CSPRNG is available (e.g. /dev/urandom or Microsoft's CAPI RNG) it uses that. You'd have to be on a pretty unusual / exotic setup for an OS-specific CSPRNG to not be available.
    – Polynomial
    Commented Dec 3, 2012 at 9:40
1

Session Identifiers should be signed then you don't have to worry about people trying to guess the session id.

Also check for collisions to make sure you haven't given away that identifier already.

1
  • 4
    Signing doesn't protect the privacy of the value. It only attests that the value came from the server. You need to actually perform a key exchange and encrypt the session key in transit to prevent it being able to be captured. The only exception to this would be if the client has a trusted certificate in which case they could sign any challenge to verify their identity to the server. Commented Apr 18, 2013 at 13:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .