4

I am working on a large web application that runs entirely within a single web-page. For various reasons we do not want to use cookies in this web application, at all, but we need to keep track of whether a user is currently logged in or not. All of our connections are over SSL. Here is how we plan to keep track of sessions:

With each response sent by the server, it sends an session token.

The session token is an encrypted string containing the following:

  • The UserID
  • A SessionID
  • A salt (randomly generated each time)
  • A current time-stamp
  • An expire time-stamp, exactly half an hour after the current time-stamp

When the client sends a request, it must also send this session token. The token is decrypted and the time-stamps are checked to see if they are half an hour apart, and that the present time is between the two time-stamps. If so, the request is processed, using the user ID to identify who made the request. If not, the request is not processed, and a response telling the client to log the user out is sent.

Will this system leave us horribly vulnerable to people falsely identifying as a user? Do you see any other problems with this?

4
  • What about a token replay? Can I take a token from another session and take over that session?
    – schroeder
    Jan 11, 2012 at 18:24
  • What do you mean when you say it includes a salt? Without a hash as part of the system, I think you may be misusing the term.
    – Jeff Ferland
    Jan 11, 2012 at 18:39
  • Yes, but the same thing would happen if you stole a session cookie. We try to prevent people from intercepting tokens by using only SSL connections. Is there something we could add to the token to prevent this? Jan 11, 2012 at 18:48
  • What I mean is that the server encrypts this data before sending it to the client, and decrypts it upon recieving it from the client. The client should not be able to see the information contained within the token, nor should anyone be able to make their own token. Jan 11, 2012 at 18:51

4 Answers 4

4

You are basically trying to store session information client-side -- not store permanently, but store nonetheless. This can be done, but is delicate.

The basic model is the following:

  • An authenticated client receives a randomly generated value, say, a "session ID". Something big enough that trying random values would have only negligible probability of hitting an existing session ID, so that it is not possible to "steal" a session. (16 random bytes are enough, if you use a strong PRNG.)

  • The session ID is sent to the client, and the client send it back for each request.

  • The server maintains client-specific data in a database (or in-memory map) indexed by the session ID, including things like the date and time of the last request from the client.

From this model, it is possible to offload some of the storage requirements on the client. This is what you suggest: with the session ID, you send some other data to the client, as an opaque blob which the client is supposed to send back unchanged with its next request. Let me highlight the important points:

  • "data to the client": this data then becomes available to the client; this may or may not be an issue, depending on the exact data. There is little problem in letting the user learn his own name or the date of his last request, since he could have guessed that by himself. Nevertheless, on a general basis, the tool for that is symmetric encryption, with a symmetric key that the server chose randomly, and never divulges to any client. Note that this can raise issues on multi-frontend servers, and servers which reboot (depending on the load balancing model, you may have to share the key between the frontends).

  • "the client is supposed to send back": what if the client, on a whim, decides not to send it back ? Or, instead of a whim, the client's connection dies ? (Power outages do happen.) If the server maintains in-memory structures indexed by the session ID, then you need some kind of automatic cleanup on timeout. You will then more or less have to forcibly "logout" inactive clients, or have them send a dummy request regularly.

  • "unchanged": the client may try to alter his blob, e.g. change the "user name" part. Contrary to what you seem to assume, encryption does not protect against alteration. Some kinds of encryption may make the task a bit uneasy or blurry for the attacker, but encryption was not meant for that, and you will not get an appropriate level of protection that way. What you want is a Message Authentication Code, which can be viewed as a kind of "keyed checksum". A MAC will let you detect, server side, unwanted alteration -- unless the "alteration" is about replacing the blob altogether with another complete blob also sent by the server, to the same or another user.

    A MAC needs the same kind of key than symmetric encryption, so it raises the same issues about key management. Also, if you want to have a MAC and to encrypt, you will be extremely tempted to use the same key for both usages. This is not a good idea. If you want to encrypt and to have a MAC, you should use a dedicated mode such as EAX, for which smart people have already found out and deactivated the pitfalls inherent to such an endeavour; or, you could try to make a homemade construction, and let your system join the horde of homemade systems which failed to be as secure as their designer initially dreamed of.

  • "its next request": The client may send blobs out-of-order, duplicating an older blob value, possibly mixing blobs from two parallel connections. Various issues may raise from such games. The blob represents the memory of your server: this is data that you trust to the client because the server does not wish to remember it itself; correspondingly, nothing prevents the client from making the server "forget" it, or "rewind" the server memory. Neither MAC or encryption can fix that. Depending on your application, this may or may not be a problem, but chances are that it is.

Finally, offloading data to the client means that you are trading network bandwidth for RAM size: you save a few bytes of RAM, but you have more data to send and receive. Economically speaking, I am not sure this is a smart move.

5

KISS -- Keep It Simple, S___ (fill in what you will).

Pass only a session id to the client. Verify that session ID on the server side. The server should map out who the session id belongs to. The server should be responsible for expiring that session ID.

Under your current system, it is unclear whether a user can change their identity by changing the username. It is also unclear what will happen if they alter the timestamps.

2
  • They should not be able to alter the timestamps or the userID, because we encrypt everything as one piece on the server, and decrypt it when we get it back. Sending only the session ID is a definite possibility, but we'd also like to store as little on the server as possible. Jan 11, 2012 at 19:00
  • That is what they said about Webforms, then an exploit led to the ability to decrypt and tamper with keys. I'd rather not increase the likelihood of that when I can just use back end session tracking. Jan 13, 2012 at 16:51
3

Althoug Tom Leek's answer has already been accepted there are a couple of points he doesn't address.

As described

  1. there is nothing here to prevent against 3rd party replays and XSRF
  2. the session identifier is bookmarkable / easily transferable
  3. it will require a large amount of custom code (more code = more errors = less secure) to manage the session
  4. for cookies you can easily restrict a session id to not be accessible to javascript and/or only be used for SSL and/or restrict to a specific path - so unless you add lots of code, the attack surface is much larger
  5. it will require lots of code to populate every possible method of navigation between pages - PHP's session management mechanism provides a mechanism for propogating a session id via GET CGI variables - but nobody uses it because they run into problems with javascript, POST forms, redirection....in addition to the other problems described above.

If you are going down the route of using a client-side value to reference server side data then don't use (a)symmetric encryption for generating the handle - if your secret is ever compromised your entire system is compromised. Use a random value and keep a lookup table serverside. (This applies regardless of where you store the session id).

Just don't even think about attempting this

0

The session token is an encrypted string...

As long as you're using a good, random, private (= not part of the transmitted data) salt and refresh (recode) the crypted string more than frequently (to prevent "replays"), it could be done.

But from a security standpoint, it's running shivers down my spine to even think about someone implementing it like that. You're showing the world data that you could and should protect.

In other words: don't do it like that!

Let me just throw in three simple questions:

  1. Since you are potentially showing the encrypted data to everyone in public, how safe is your encrypted data which when it comes to reverse-engineering your crypto implementation?
  2. What about brute-force attacks and how are you planning to defend yourself from those as your system can't know if the data passed has been messed with (example: re-encoded token containing different data like another IP)?
  3. Do you know that - by providing the salt with the crypted data - you are actually providing part of the key needed to decode the data you're transmitting?

So, one of the most important reasons not to do what you do is that you can not verify the data validity of your token or it's contained, crypted data.

Also, providing the salt you're using together with your crypted data is an absolute "no-no" because such a salt should be kept absolutely private. It is "part of the mix" which should actually make brute-forcing harder. Publishing the salt with the encrypted data voids the purpose of the salt and makes it as easy as if there weren't any salt!

In the end, you always need remind yourself of the fact that poor or wrong implemented cryptographic and/or security procedures will never be able to protect you as expected. From what I've been reading in the description that comes with your question, I'm sorry to say that you're doing it wrong in several areas.

You must log in to answer this question.

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