Client Side vs Server Side Session
We recently looked at replacing our legacy session management system with a new one. During this analysis, we came close to choosing a client side session but eventually concluded server side was better for us. Here's why...
In this model, all session state is stored in the client in a cookie. The benefits of this are you don't need to worry about persisting and replicating state across nodes, session validation is lightning fast since you don't need to query any data store which means it's super scalable. The session cookie must obviously be tamper proof (to prevent people creating a session of their choice) which is achieved by signing the cookie using asymmetric cryptography.
The signing of a cookie value uses the private key, the validation uses the corresponding public key. Our idea was to try and keep the private key as private as possible by storing it in memory only. Each node (4 shown below) would create a new private and public key on startup, with the public key being persisted in a replicated data-store. This means (providing replication is working) any node is able to validate a session created (signed) by any other node.
Benefits of a client side session:
This is the traditional model which relies on storing all state in a replicated server side data-store. The cookie is tiny as it only stores a reference to data stored on your server.
Session Timeout. We decided that after 30 minutes of a user's inactivity, we are obliged to log them out if they have elected to not "Remember me". Relying on the user closing the browser, we decided, is not enough. This means that you need to store a rolling timeout which gets updated on each page view (this is in addition to the hard timeout discussed regarding session termination). This requirement makes the client side session a lot more complicated since each time a page is viewed, the session must be updated, re-signed and dropped (Set-Cookie) back to the user.
Client side session
In this model, all session state is stored in the client in a cookie. The benefits of this are you don't need to worry about persisting and replicating state across nodes, session validation is lightning fast since you don't need to query any data store which means it's super scalable. The session cookie must obviously be tamper proof (to prevent people creating a session of their choice) which is achieved by signing the cookie using asymmetric cryptography.
The signing of a cookie value uses the private key, the validation uses the corresponding public key. Our idea was to try and keep the private key as private as possible by storing it in memory only. Each node (4 shown below) would create a new private and public key on startup, with the public key being persisted in a replicated data-store. This means (providing replication is working) any node is able to validate a session created (signed) by any other node.
Benefits of a client side session:
- Low Latency - Validating and creating sessions is lightning fast as it doesn't need to hit the data-store.
- Fewer points of failure - DB is only required on startup of each node.
- Highly scalable since it's stateless (slight caveat of replicated public keys).
- Possibility of distributing validation away from application nodes. If the public keys are exposed via an api (provided by the nodes shown above), this means any other system can validate a session without having to make a synchronous call. This makes session validation even quicker in a distributed system.
Cons of a client side session:
- Sessions cannot be terminated (there are workarounds to this which I'll get to).
- Logout action is not fully implemented - The session cookie can be dropped from the browser, but it would still work if resubmitted.
- Implementation and user details are exposed since everything is stored in a cookie.
- Cookie size is greater - Sounds trivial but can cause huge headaches (see below).
- No 3rd party frameworks available (none in Java we could find anyway).
Terminating a client side session
This can be achieved by setting an absolute timeout on session create to a long period of time (say 1-2 days) which, when exceeded, will cause the session to be invalid and force the user to re-authenticate.
Keeping cookie size to a minimum
This is a trade-off between complexity (in terms of parsing and maintaining sessions), security (strength of signature) and cookie size. Maintainability is important given that your state will be living "in the wild" in your many clients' browsers. If you ever want to add, remove or change an attribute in your users' sessions keep in mind you will need to support the two versions of your cookie as you deploy your changes.
The simplest thing to do with your data is to Base64 encode it (careful of the padding character, the default is a non-cookie friendly equals) using a format such as JSON or XML. Using such a format comes with the benefit of readability and maintainability.
To get the cookie size down to a minimum, a list with a cookie safe delimiter (e.g. a dot) and effectively encoded/compressed could be the way to go
The more secure the signature, the more space it will consume in the cookie. For example, signing 46 bytes of ASCII characters gives:
87 byte signature using a 512 bit key to sign.
172 byte signature using a 1024 bit key to sign.
The simplest thing to do with your data is to Base64 encode it (careful of the padding character, the default is a non-cookie friendly equals) using a format such as JSON or XML. Using such a format comes with the benefit of readability and maintainability.
To get the cookie size down to a minimum, a list with a cookie safe delimiter (e.g. a dot) and effectively encoded/compressed could be the way to go
The more secure the signature, the more space it will consume in the cookie. For example, signing 46 bytes of ASCII characters gives:
87 byte signature using a 512 bit key to sign.
172 byte signature using a 1024 bit key to sign.
Server Side Session
This is the traditional model which relies on storing all state in a replicated server side data-store. The cookie is tiny as it only stores a reference to data stored on your server.
Benefits of a server side session:
- Full control of session - Can terminate a session on demand instantly.
- Existing frameworks can reduce amount of custom code to develop/support - See Apache Shiro
- Cookie size is much smaller.
- Implementation and user details are not exposed since only reference to session data is stored in the cookie.
- Can store as much session related data without fear of increasing cookie size.
- Implementation of session management can change easily since we store the session state ourselves and is not “in the wild” (i.e. not stored on many different browsers).
Cons of a server side session:
- More points of failure - If the DB is unavailable, no sessions can be created touched or validated
- More overhead in creating and touching session (a DB read, write and replication is required). This can be mitigated by applying the DB write asynchronously.
- No future potential for applications to verify session without having to call nodes.
The points that swung the balance to server side
Session Timeout. We decided that after 30 minutes of a user's inactivity, we are obliged to log them out if they have elected to not "Remember me". Relying on the user closing the browser, we decided, is not enough. This means that you need to store a rolling timeout which gets updated on each page view (this is in addition to the hard timeout discussed regarding session termination). This requirement makes the client side session a lot more complicated since each time a page is viewed, the session must be updated, re-signed and dropped (Set-Cookie) back to the user.
Being able to kill sessions can be useful.
There are rare occasions when we want to kill a user session. Sometimes this is a business reason, for example if we suspect that a user has shared their credentials with other people. It is also reassuring to know we could terminate user sessions immediately in case of a security breach, e.g. hi-jacked accounts. This just isn't possible with a client side session. When you start trying to solve this issue with server side state it is my opinion that you have the worst of both worlds (i.e. the complexity of client side signing and server side replicated state).
Cookie size
If cookies get too big the impact can be huge, worst case your users see a blank page with something in your stack returning a 431 status code. This is due to the request headers exceeding a certain limit. How do you know when you'll exceed the limit? How do you know what your limit is? In a distributed system with multiple entry points, your maximum http header size might vary. This could cause (seemingly) random pieces of functionality to fail for users with big cookies.
On balance, the server side session is the solution for us. However, if your organisation has different requirements, the client side session is worth a look.
Very informative. Thanks you Sir.
ReplyDeletePratap
Extremely useful.
ReplyDeleteGreat post.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteInteresting, but why asymmetric cryptography. If I understand it correctly, http://pythonhosted.org/itsdangerous/ uses symmetric cryptography. Shorter signature and less computational overhead.
ReplyDeleteI have a many unsolved worries about having session state on client-side, with this article i understood a possible approach on how to build a client side session management system. Also the analysis is very Interesting.
ReplyDelete