Doing HTTP Sessions badly

In this article I explore some ways in which HTTP sessions can be used badly. I'm not talking from a church of RESTafarianism position here. I'm cool with web applications using HTTP sessions, but I want to explore the pitfalls of using them badly and given some easily followed guidance to make their use safer.

Imagine you have a web application and you are making changes to the session. These changes affect downstream resource access or display in the application. What happens if some of your session updates happen and others don't? Will your application behave properly?

A pattern I've seen in few applications I've worked on and in some tutorials as well is updating the server-side HTTP session map at arbitrary times during request processing. Essentially updating fragments of the session state as soon as the information available for that fragment is available. This seems like good, efficient programming, but I'll explain why it is a very bad idea.

I'll start with a strawman, but regrettably it's a strawman I've seen in practice. Imagine that you have a username attribute in your session. During login you might set the username. Why not set it as soon as you receive the form? Okay, done. Now your next step is to validate the password. Your code checks the password and it is correct. The user is logged in. Hunky-dory, right?

First, let's look at a trivial case that seems to suggest that this is okay. The user logs in with an incorrect password. The system sets the username, but finds the password to be incorrect, so it invalidates the session, dropping the server-side session map for that session ID. All good, right?

Wrong. This doesn't fully work and gets worse as the login process gets (inevitably) complicated by new requirements like password resets and new user activation. How so? Between setting the username on the session (blessing it as authenticated for further requests) and actually authenticating there are now a range of possible crash scenarios. Crashing the login becomes a means of becoming anyone whose username the attacker knows. Why does this attack work? It works because the crash prevents the invalidation.

How do we fix this? The naive answer is to ensure that the invalidation happens. That will work so long as new code doesn't introduce new crash paths unprotected by the mitigation you introduce. That's wishful thinking at best. It is far better to instead delay the establishment of an HTTP session and variables within it until after the authentication flow is complete and validated. In a sense this is like organizing database updates into a transaction. Like a financial transfer you don't want the debit or credit or one account to happen without the corresponding credit or debit of the other account.

If you want your sessions to be ACID as in database transactions, rather than acid as in LSD, I strongly recommend delaying the establishment of authentication-sensitive session attributes until after authentication is confirmed successful.