38

Summary

Once a user logs into a web site and his username/password credentials are verified and an active session is established, is it possible to avoid hitting the DB for each and every request from that user? What is the recommended method of securely authenticating subsequent requests for the life of the session, while minimizing DB queries and other internal network traffic?

Background

In a stateless web app server architecture, where each request has no knowledge of any prior activity from the user, it would be necessary to query the DB on each and every request from that user (typically by querying the session ID stored in a cookie and transferred in the request header). But what if some basic information was encrypted and stored in that Session cookie that had enough information to validate the user for non-sensitive, non-editable requests? For such requests, you could as an example encrypt and store the user ID and something that uniquely identifies his machine as much as possible (user-agent + ip address) in the Session data. The key used to encrypt the data could change daily making it difficult for any hacker to clone the Session data on a different machine. When the Session expires you would need to fully validate the user's credentials. The fact is, the biggest threat to hacking a user's session would be someone using a user's computer that he or she left unattended. Should I just not worry about this and let some level of caching between the web app servers and the DB take care of expediting the authentication process? While it may seem to be unnecessary optimization, it seems like a candidate ripe for improvements in efficiency since each and every request requires this process. Thanks for any suggestions!

onlinespending
  • 483
  • 1
  • 5
  • 6
  • You could consider using applications like memcache or reddis to abstract storage of the session state to the application level rather than requiring ongoing interrogation of the database to maintain this. Or does the stateless nature of the architecture prevent use of these? – AndyMac Jan 22 '14 at 04:22
  • @AndyMac I'm using Cassandra for the database. Since each application server is insulated from each other and autonomous, it would seem using something like memcached or Redis wouldn't buy me anything over using Cassandra. They couldn't be implemented locally on each App server, and would need to be distributed just like the Cassandra cluster. – onlinespending Jan 22 '14 at 05:09
  • @onlinespending If web app server is `stateless`, why there's still `session` on server? The state info should all live on client side. – smwikipedia Jan 06 '16 at 03:50

4 Answers4

42

Yes it is possible, and this technique is widely used.

It does have some minor drawbacks compared to stateful sessions:

  1. It does not support strong logout. If a user clicks logout, the cookie is cleared from their browser. However, if an attacker has captured the cookie, they can continue to use it until the cookie expires.
  2. The use of a server-side secret to create the tokens creates a single point of failure: if the secret is captured, an attacker can impersonate any user.

Deciding whether to use stateless or stateful sessions depends on your performance and security requirements. Online banking would tend of use stateful sessions, while a busy blog would tend to use stateless sessions.

A few tweaks are required to your proposed scheme:

  1. Encrypting the token does not protect it from tampering. You want to use a Message Authentication Code (MAC) which does protect tampering. You may additionally want to use encryption, but that is less important.
  2. You need to include a timestamp in the token and put a time limit on their validity. Somewhere around 15 minutes is sensible. Normally you would automatically re-issue shortly before the timeout, and usually the reissue would incur a database hit (although even that can be avoided)
  3. Do not include the user's IP address in the token. Approximately 3% of users will legitimately change IP address during a web session, due to modem resets, changing WiFi hot spots, load balanced proxies and more. While you can include the user agent in the token, it is not normal to do that - consider it an advanced technique to use if you are sure you know what you're doing.
  4. If an attacker captures a session cookie they can impersonate that user. There is nothing you can really do about. Instead, put all your effort into preventing an attacker capturing the cookie in the first place. Use SSL, use the "secure" cookie flag, fix all cross-site scripting flaws, etc. And have some user advice to lock their screen when their computer is unattended.

I hope this is helpful to you. If anything is unclear or you need further information, leave a comment and I will see if I can help you further.

paj28
  • 32,736
  • 8
  • 92
  • 130
  • 1
    Thanks for your helpful answer. In regards to your 2nd concern, I would change secrets on the server very often. In fact, wouldn't it be possible to change secrets say every 15 minutes in lieu of a timestamp to time out a token? If a token is sent that is using an old secret it would be invalid, necessitating a full login by the user. You could validate a token that uses both the current secret and the prior one (to allow seemless reissues). Anything else would be invalidated. – onlinespending Jan 22 '14 at 17:13
  • 1
    Regarding #3 where'd you get the 3% stat from? I'd like to read up on that. – Steve Jan 22 '14 at 18:42
  • 1
    @SteveS original research I did using my website. It is old, but I expect the figure is still broadly correct. It's written up in this paper: http://www.westpoint.ltd.uk/advisories/Paul_Johnston_GSEC.pdf – paj28 Jan 22 '14 at 21:42
  • @onlinespending Changing the server secret every 15 minutes... interesting idea. I've not seen it implemented - most sites simply accept the risk - but I think it could work. – paj28 Jan 22 '14 at 21:43
  • How does a 'Remember Me' cookie affect things, especially with regards to timestamp and the life of a session? It seems as though this would break your 2nd rule of keeping a short time limit on the validity of a token. Since I'm not doing anything financial related, I'm curious how a site like Facebook handles sessions. If it's good for a company that handles 1 billion users, then it's probably good for me. – onlinespending Jan 22 '14 at 22:15
  • 1
    @onlinespending I've not looked at how Facebook do it, but I expect the "remember me" cookie is stateful and requires a database access to verify, while the session cookie is stateless. Actually, I've not looked at many sites in detail that use stateless cookies - most clients that commission pen tests are security sensitive and go down the stateful route. Facebook may well be fully stateful, as every page load requires database access anyway, so it may be little performance hit for them. – paj28 Jan 22 '14 at 22:26
16

Generically, it is possible to "store" state information on the client, even sensitive information such as authentication data; such storage is used to save resources on the server, e.g. to minimize database load. See these previous questions:

In a nutshell, whenever you want to store some information s on the server, to be looked up if the same client comes back, you can instead send it as a cookie to the client. You may want encryption because that information might be "private", in the sense that you do not want to show it to the client himself. You probably want integrity because you do not want the client to be able to alter the data without your consent. So you want both encryption and a MAC, or, better yet, one of these nifty encryption modes which do both properly (GCM being the often quoted standard for that).

As generically, when you store state information on the client and the client, then you lose some control over the life cycle of that information. The client may elect not to send back the cookie, i.e. simulating a new, fresh client; also, the client may send back an old cookie value. Whether this is a problem for you depends on your exact situation. You will probably want to include in the cookie data a time stamp, allowing you to recognize cookie values which are really too old.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
1

There are some ways to achieve this problem (and I have seen this approach used in REST APIs).

  1. Using HTTPs to authenticate and then use the stateless API.
  2. Using a basic HTTP authentication method and use an expiring tokenID in each request.

In any way, if you need authentication and stateless you will need manage the authentication in your app session. After verifying the credentials you can actually make the database query without authoring it again via trusted user or similar.

Be sure not to allow direct connection to the database from any other user than the one you have allowed to do so after the credentials check.

kiBytes
  • 3,450
  • 15
  • 26
0

I am sure that you understand that to omit an authentication based on a previous authentication makes your web application a session application. Isn’t it a session state been authenticated? Know that you are studding to have a session; you may ask yourself why you required a session lees application. Normally people want session lees applications for two main reasons: Requests can be delivered to different servers without worrying of any dependency between client and any member of a server farm. Memory linkage when a large number of users are accessing concurrently. Even on session applications you can meet those requirements by making the server to issue an encrypted signed token when the authentication so other members of the web farm can verify that token to have an idea that the user might be legitimate. Impersonation is still possible because following request need the same token. You can include in the token data from request http headers and IPs to restrict its use but middle proxies can still use the token by doing NAT and copying the client headers. Then only way to make invulnerable to man in the middle attacks is by protecting the authentication request by https and letting the client send you with the credentials a random generated key that will be used to decrypt the signature of the request, the client in each request will encrypt some data of the request as a signature. The data encrypted can be the session ID and a sequence element from a pre-establish sequencer generator. Do not use the simple incremented by one because of its predicable behavior. As in each request this signature is different from previous signatures, you can be sure that client is authenticated. If sequencer generator it always incrementing you can cache the last element used to make a simple check previous to a full check; broadcasting other members of the farm the element of the sequence used within the session ID and they will only answer if the element is invalid. An element sequence is invalid if it has been used in previous request in the answering server or if next elements of the sequence time out in the cache. Preventing memory linage is a simple a implementing an SQL server for each member farm to make this info persisted and have in memory only the most frequently used information. The devices of network used for communication between farm members must be all administrated by the owner of the application because the communication is insecure. With this structure scalability is assured.