2

Instead of a server issuing randomly generated session strings as service access keys (aka "authentication tokens") to a client, inserting them into database to maintain a set of user-key relations, for subsequent validation on every service request, may a server not do the following instead to achieve comparable or better security in the thus distributed system:

  1. Take the user's primary key (aka "user identifier")
  2. Take a chosen key expiration timestamp, and, optionally, the IP address of the client, and whatever else may be worth embedding in the key
  3. Take a secret string as the key verification signature
  4. Serialize all of the above
  5. Encrypt the result, symmetrically, with a key only known to the server, or asymmetrically using server's chosen private key

The session key that is the result of the steps above, is then shared with the client, e.g. with a cookie. With a stateless protocol like HTTP, where every request has to prove client authentication using a session key, the procedure described above is done in reverse by the server, with the goal of recovering an authenticated user identifier.

Everything else being equal, a successful attack on the underlying cryptography would be required for an adversary to be able to forge session keys and thus compromise the security of this system. With "everything else" I refer to weaknesses like the adversary obtaining user's session key from the client somehow with the intention to use it themselves.

The advantages of the approach, that I see, are:

  1. No need to maintain a valid user-key relation set anywhere
  2. Expiration value embedded in each key ensures that keys cannot be used beyond a certain point in time, by anyone.
  3. Decryption-based verification by the server may be less costly than database access.

The disadvantages may be:

  1. Invalidating keys by the server may be considered problematic:
    • Even if a key securely embeds e.g. an IP address, where the server may use the latter to validate the key by comparing the embedded address to the address behind the service request, an IP address may be forged
    • If key revocation problem is solved by the server maintaining a set of revoked keys, one may ask how this is better than maintaining a set of user-key relations in the first place?

I consider this question closed as it may not ever have a single acceptable answer and does not hence fit the SO guidelines, but since it has remained open and has gotten useful answers, I won't delete it, at least.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95

4 Answers4

2

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
  • 73,905
  • 40
  • 169
  • 246
  • 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? – Armen Michaeli Feb 06 '10 at 12:52
  • Yes, I am considering HTTPS (courtesy of PHP's OpenSSL) for serving private resources to the user. – Armen Michaeli Feb 06 '10 at 13:25
  • @amn I'll update the answer to explain why you don't need to worry – Will Feb 06 '10 at 14:41
  • See my comment to your comment why I still don't really like the basic concept but +1, good answer. – Pekka Feb 06 '10 at 16:18
  • I've added a link to "straightforward" claim, because encrypting cookies is *not* straightforward :) – Will Feb 06 '10 at 19:00
  • 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 Feb 07 '10 at 00:06
1

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
  • 4,528
  • 7
  • 38
  • 43
  • 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. – Armen Michaeli Feb 06 '10 at 13:21
0

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
  • 31
  • 5
0

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.

Community
  • 1
  • 1
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • 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 Feb 06 '10 at 15:01
  • @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 Feb 06 '10 at 16:17
  • 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. – Armen Michaeli Feb 06 '10 at 18:41
  • 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 Feb 06 '10 at 18:52