A Tale of Two Sessions
What are sessions?
Sessions are the means to identify users of your websites during subsequent requests without requiring them to pass along their username and password with each request.
Typically this is done by associating a unique session ID with a user in the database.
There are two primary methods of identifying a user session:
- Storing a Session ID in an unencrypted cookie
- Storing the User ID in an encrypted cookie
Most frequently the Session ID is stored in a cookie, which is used to load the active user and any metadata from a database when a request is made to the server.
In the past few years, storing the sessions in cookies themselves has become more popular. Doing this removes some application state which can be challenging to manage for each request. The web developer doesn’t have to run an additional service (like memcache or redis) or put additional load on their primary database.
Server Side Sessions w/ cookies
This is the original method for managing sessions and is still the most common. It requires storing session information in a database. Web developers often start by storing it in their primary database, then move towards redis or memcache as traffic to their web application grows.
The cookie for this method of session management typically looks something like this:
Revocation is easy: you only have to delete the Session ID from the sessions table, wherever it is stored.
Storing sessions in encrypted cookies is becoming increasingly popular because it removes the need to retain state server-side. However, it requires the operator to maintain an encryption key to authenticate that it was indeed the server who set the session cookie in the first place.
The cookie for this method of session management typically looks like this:
Revocation is not so easy. You either have to wait until the session expires (bad), construct a way to communicate to all the web application servers that this session has been revoked and must be re-authenticated (complicated), or check the session is valid for every request.
Comparison of Security Threat Models
Some may think that encrypted cookies are more secure because: duh they’re encrypted! In fact, encryption has nothing to do with keeping the user or an attacker from knowing what the cookie is. Instead it is a means to communicate from one web-server to another that this cookie was not modified in transit or forged by an attacker. A simple nonce and signature would work just as well in this regard (django does this).
For that matter, stealing an encrypted session cookie is just as effective at impersonating a user as stealing an unencrypted session cookie. Just because an attacker can’t read an encrypted cookie doesn’t mean it won’t authenticate them as the user just as well. Because of this property, all cookies used for authentication must be Secure only. The Secure attribute on cookies indicates that it should only be sent over a TLS connection.
The primary security drawback to using encrypted cookies over normal session cookies is that you have traded a state management problem for a secrets management problem. These secrets are often populated in environment variables and these environment variables are occasionally logged accidentally or mishandled in some other way. Once it’s out, rolling the key is required, invalidating all active user sessions.
Comparison of the Benefits
The primary benefit of encrypted cookies is statelessness. No more database table for sessions, no more redis or memcache to manage in addition to your existing database.
The primary benefits of plain ol’ sessions are also the drawbacks for using encrypted cookies:
- easy revocation
- one less secret to manage
Revoking a session when using server-side sessions is simply deleting that user’s session from the sessions table in the database. Session revocation can happen for numerous reasons:
- User changed password
- User got hacked and wants to revoke all existing sessions
- User’s privilege level changed
- User deletes account
If you build a system to handle this using encrypted session cookies, it will probably look very similar to plain ol’ sessions.
Why I wrote Jeff
Jeff is a tool for managing sessions in Go.
You might have been able to gather from this post that I’m firmly in the camp
of using server-side sessions for session management. Because of this, when I
started looking around for session libraries in Go, I noticed that all the ones
I could find either used encrypted cookie storage, had bloated APIs, or were
not idiomatic. Additionally, they almost all missed embedding
context.Context, which is an important feature to support request
So I went about implementing my own. Among it’s features:
- Small, simple API
- Supports context
- Supports arbitrary storage backends
- Secure by default
- Handler wrappers
- Supply custom redirect handler
Additional Resources on Sessions
In popular web frameworks:
Using JWTs for Sessions (JSON Web Tokens are standardized encrypted blobs):
These guides talk about implementing sessions, but are not (what I would consider) very idiomatic: