views:

62

answers:

4

This time I am going to be brief :-)

Instead of issuing randomly generated session strings to a user and inserting them into database, mapping these to user identifiers, for subsequent lookup on every authentication, why not do the following, with the intention to avoid database access on every request and distribute the session store instead:

  1. Take the user's identifier
  2. Take a chosen expiry (date and) time
  3. Put the two above together
  4. Pad them with a 'salt' - here a secret string of (a longer) arbitrary length
  5. Encrypt the resultant string with a secret encryption key

The result would be a string that is sent to the user (using HTTP Cookie mechanism) as the session key. Obviously, on authentication, the procedure is reversed by the server again, to extract a user identifier. If the expiry datetime checks out, that is. The session string would be considered infeasible for the client to cook up himself, because a brute-force attack is required where a large amount of salts and large amount of decryption keys will have to be tried, plus a correct structure of the unencrypted data has to be guessed.

My question is: what are the security related implications of the method I outlined? In my opinion, obvious advantages are:

  1. The sessions are not in a centralized store, but are distributed instead.
  2. Expiration value still ensures that these distributed sessions do not circulate indefinitely.
  3. If decryption is speedier and less complicated than database access, the method is obviously faster as well.
A: 

I like this method and I use it for my websites because it's easy to scale with that.

The only security issue I see with this protocol on HTTP is that your requests are vulnerable to replay attacks/sniffing. By the way, the same issue exists with session IDs stored in cookies on a non encrypted transport protocol, except if you regenerate the session ID on each request.

Extra reading : a PHP implementation wich includes a link to a great paper on this subject (sorry I can't post more than one link on stackoverflow at the moment ;).

Mat
A: 

What do you want to use to encrypt/decrypt the data?

Generally, I wouldn't suggest doing what you told us about above because:

  • Why not have all the sessions in a centralized store? Your encryption algorithm could be stolen/cracked as well.
  • Database access will be most likely faster and easier to manage/code

If your source code is stolen or the algorithm is broken, attackers could create new, custom session and make themselves admin - you can image the rest yourself

Have you though about using the standard session library in PHP?

lamas
You have some very valid points. I have thought about this and it is much more clear to me what the implications are. P.S. Yes, I do currently use PHP session API - i don't like to reinvent the wheel, but the question arose out of general interest in security topics.
amn
+2  A: 

The weakness of the system is that the 'logged in' token is sent plaintext in a cookie, and this is the same weakness whether the token is in a database or not, and is guarded against by using HTTPS connections.

Having said that, most sites don't use HTTPS. They make a trade-off. If you don't use HTTPS, and you want to compare sending a authenticated cookie vs sending a cookie is a database key, then there is nothing week in the former compared to the latter.

It is a good idea to include also the IP address of the request as well as the expiry date.

It is unnecessary to store the token encrypted in the cookie, however - it is equally secure and rather more straightforward to send plain-text credentials and then a cryptographically secure hash of the credentials and the secret. See HMAC for details. HMAC is basically:

Imagine that the variables username, expires, ip_address and a salt (a random number) have been stored in the HttpOnly cookie; you extract them, as well as your hash that was also in the cookie. In your script you have an additional 'password', which is never directly stored in the cookie:

hash = hash_hmac("sha256",username+expires+ip_address+salt,"password")

The security of this hash is based upon the quality of the password. This should be some random string of digits and letters and punctuation and be at least 20 characters long, which is stored in your server-side scripts.

If the hash in the cookie is correct, you can be certain that the fields that were hashed have not been tampered with! The chances of an attacker generating a meaningful collision would be gazillions to one [1] - certainly beyond the compute power of all the computers in the universe and a bazillion years. Its that secure, if your password is something sensibly random.

But the whole system is only a speed-bump to a determined attacker, and is only appropriate for normal websites rather than things including payment or a user-expectation of security. Without HTTPS the system is not secure, and with HTTPS the authentication of the cookies is unnecessary.

A determined attacker could access your site to recover the password - there is nothing stopping them recovering the login details to a database in the same circumstances, so no different from the database approach outlined in the question in this regard.

A determined attacker could copy the credentials, and send nasty requests on behalf of the user, e.g. csrf and so on.

And so on.

[1] I understate the odds.

Will
Thanks. Wouldn't sending both the plaintext and a secure hash of said plaintext make it easier for the attacker to figure out the exact method used to produce a valid hash for a valid plaintext? Without using some random salt, all he/she would have to do first is to try the most popular hash functions - md5, sha1, sha256, des etc, bcrypt. Suppose I use the latter - without a salt used to hash the plaintext, surely his mission is accomplished?
amn
Yes, I am considering HTTPS (courtesy of PHP's OpenSSL) for serving private resources to the user.
amn
@amn I'll update the answer to explain why you don't need to worry
Will
See my comment to your comment why I still don't really like the basic concept but +1, good answer.
Pekka
I've added a link to "straightforward" claim, because encrypting cookies is *not* straightforward :)
Will
There's no point in tracking the IP address - many clients can seem to be connecting from the same IP. A single session can arrive at your server by different routes and therefore appear to have multiple ip addresses.The biggest drawback for me with this method is the limited amount of information which can be stored in a single cookie - but if all you need is the username then its as secure a method as a session - but do set the http-only flag on the cookie.
symcbean
A: 

Not a good idea. A very similar (and fundamentally, if I understand correctly, indentical) question has been asked a few weeks back. My answer was (I added the emphasis to underline the core point):

Storing vital data like session expiry and user name entirely on client side is too dangerous IMO, encrypted or not. Even if the concept is technically safe in itself (I can't answer that in depth, I'm no encryption expert), a break-in could be facilitated without compromising your server, just by acquiring your encryption key.

Somebody who gets hold of the key could generate session cookies at will, impersonating any user for any length of time, something the classical session concept with its centralized storage of session data is designed to prevent.

There are better and scalable solutions for this problem. Why not, for instance, set up a central session verification instance that all associated servers and services can poll? Look around on the web, I am 100% sure there are ready-made solutions addressing your needs.

Pekka
I think you overstate the issue; an attacker could do impersonate users whose credentials they see in transit over the internet whether there is an oracle or otherwise.
Will
@Will, getting hold of login data the way you describe requires eavesdropping on somebody actually logging in. The same goes for session hijacking. Not so with the OP's method: One would just have to find an old, expired session (or loads of then, in a browser cache for example or a link somebody passed on, to improve the odds) and could have an unlimited amount of computing power work on it until they manage to decrypt it. I still find that, even though theoretical, a tremendous weakness but having read your answer, I agree it's not as much a risk as I thought.
Pekka
One thing that alarms me with client-side sessions (as the "very similiar" question calls them - a good name btw) is that they indeed may be suspectible to 'crib' attacks, right? - I mean, if an attacker knows that somewhere in the plaintext there is a integer user identifier in the range (M,N) which he knows by say, inspecting site GET URLs, and a timestamp with a range (K,L) (not hard to to guess) - would it make it easier for him to figure out the encryption used including, possibly, the key itself? If so, then this is a strong argument agianst client-side sessions.
amn
If the key is sufficiently random, then no, a determined attacker cannot reverse it. There are no published attacks against SHA256 HMACs, for example.
Will