While performing a manual penetration test recently, I encountered a session management system that flew in the face of almost all the recommended security practices. Rather than use a pre-built implementation associated with a development framework, the developers had written one from scratch that, among other things:
- Generated session tokens based on the user ID and numeric counters.
- Appended the session token to the end of every URL rather than using a cookie.
- Allowed multiple concurrent sessions for a single user.
- Did not destroy the session when a user clicked “Sign Off”.
I discovered to my surprise that sessions would terminate after about an hour of inactivity, so it wasn’t all bad.
Still, the combination of the flaws above could lead to accounts being hijacked both through a purposeful attack, but also through user naivety. An attacker could perform a brute-force search for valid sessions by generating possible session tokens (since the tokens are based on known counter values and a numeric user ID). The number of possible session tokens per account was 100,000, meaning valid sessions could be found within a matter of minutes provided the user ID was valid.
Perhaps more serious is an attack which works due to user naivety when it comes to sharing information online. If a user wanted to send a link to a colleague, most would copy and paste the link without considering it contained sensitive session information. Unfortunately, in this case, every link in the application contained the user’s current session token. A person who clicks on such a link would be instantly logged into a valid session.
The session token within each URL also causes issues if a shared computer is used, as the token will be saved to the browser history, and the cache. If the application loads third party resources (e.g. JavaScript files) then the session token will be sent to that third party as part of the often overlooked “Referer” HTTP header. Assuming the third-party server has logs enabled, they would be full of valid session tokens for every user.
As I hinted at in the blog title, secure implementation of session management doesn’t have to be as complicated as trying to roll out your own in-house version. A decade ago we would not have recommended using the session management schemes found in development frameworks, but these days they have been rigorously tested and are often used in secure applications. As always, there will be potential weaknesses in these schemes, which is why it is important for developers to ensure they are using the latest version of the framework, and securely configure any session management options accordingly.