Writing your first encrypted DB-backed session store with sliding timeout
If you’ve ever caught yourself pushing large encrypted content into the standard
Plug.Session.COOKIE store, you may have noticed that hitting the 4096-byte cookie size limit isn't all that difficult. And if that hard limit becomes a deal breaker, next you'd probably be inclined to reach for
Plug.Session.ETS which in turn comes with the small gotcha that if your app runs in a distributed environment, now you'll have to deal with syncing ETS tables across nodes - something you may or may not be comfortable with.
In this post, we’ll explore another option, that is, rolling your own DB-backed session store. Using the tests of both of the said stores as a guideline, we’ll write ourselves an implementation of
Plug.Session.Store that supports session expiry after inactivity and after adding optional signing and encryption to it, we'll wrap up by briefly discussing an important caveat.
To start off with the simplest thing that could possibly work, here’s our initial version that uses Erlang’s
term_to_binary/1 to write data into the
Commits on GitHub
Signing and Encryption
The commit below has full details but the brass tacks are we add optional calls to
Plug.Crypto.MessageEncryptor.encrypt/3, respectively. For example:
Commits on GitHub
Something we’d obviously want to do before going live with our store is to whip up an Oban worker or an equivalent for periodically cleaning up expired sessions.
Another pending issue is that with the cookie store now replaced with a database-backed implementation, we have to be vigilant about session fixation attacks. What OWASP instructs us to do here is to Renew the Session ID After Any Privilege Level Change.
The session ID must be renewed or regenerated by the web application after any privilege level change within the associated user session. […]
For all these web application critical pages, previous session IDs have to be ignored, a new session ID must be assigned to every new request received for the critical resource, and the old or previous session ID must be destroyed.
Luckily for us,
Plug.Conn.configure_session/2 helps us do just that. In a Phoenix app, you'd rotate the session like so:
after which dropping the session looks oddly familiar:
That’s it. Be sure to check out the repo and as always, comments and PRs are welcome.