What exactly is session management?
To start off we must define what session management entails, especially in a modern world with ‘stateless’ (RESTful) APIs popping up everywhere. It is becoming more common to see modern technologies such as Java Web Tokens (JWT) tacked onto these APIs and actually making them semi-stateful. So, what is session management?
Session management is simply the practice of enabling a user session within your application and how long that session may persist. To a lesser extent it may even involve handling authorizations in a way and as such session management is a component of authentication and authorization together in this sense.
Let’s picture a couple examples of common session management scenarios:
A traditional web application such as your email or online banking:
You post to a form and receive a session cookie if you were successful.
Your browser now submits that session cookie with each request to the application.
The application may expire that cookie server-side, or invalidate it upon you pressing logout.
A modern REST API:
You post your credentials to an endpoint and receive a JWT, or other value to place in an authorization header.
All of your requests to authenticated endpoints contain this JWT, or other value, generally in the headers section.
The JWT has an expiration by default upon creation, but do your other methods of authenticating a user use one?
Can the user invalidate their token in some way? Maybe by changing a password, or requesting some form of logout/de-authentication.
This is by no means covering all possible implementations of session management, but handles the two biggest use cases we have seen.
If you have been the recipient of a web app pentest in the past decade or more it is highly likely at least once that you saw a session management security flaw.
They are very common, and typically come with low severities, and often as such are not remediated. The session management flaws we call out regularly fall into a few categories which I will break down. I will also address why these should be remediated even though they are low severity findings.
Excessive Session Timeout
Session Not Invalidated On Logout
Session Not Invalidated On Password Change
(Rarely) Concurrent Sessions Allowed
(Oldschool) Session Fixation
So lets dive into each of these issues!
This finding is pretty self explanatory. If you have ever been logged into a sensitive application like an HR app, or banking app, you will likely have seen a popup asking about timing you out. Basically, this finding simply means, with respect to the sensitivity of the data in the app, your sessions are allowed to live without activity for too long. This is a super easy fix as in this scenario you DO have a timeout, it is just longer than it needs to be. This is also one low that we understand risk accepting over fixing per se. The actual risk here is heavily dependent on the exposure of the app (is it for customers, internal customer support, etc.), and what the actual excessive time is. These are reported oftentimes because testers have general guidelines, like no more than 30 minutes, so communicate with your tester if you already have a policy in place.
When a user logs out of their session they expect it to be ended. It even often includes a nice popup or landing page letting them know their session is securely ended. So lets definitely make sure we DID end it! This finding comes from allowing a user to go through your logout workflow, and simply deleting the cookie in their browser, or redirecting them to the login page. These actions do not actually prevent the re-use of the session token by an attacker who has intercepted it as the session was not properly invalidated server-side. Make sure in your apps you grab the value of the session identifier submit by your user upon hitting the logout workflow and tell your app to invalidate that session.
I think this issue is probably even more important than the last one. If I think my account has been compromised the advice to me as a user has always been to change my password. Well, if my old sessions which potentially are being abused are still active upon changing the password then that has done nothing for me! An attacker can just change the password, or simply keep interacting with the app in their live session. With a combo web app and API where your users generate their own API tokens also invalidate those API tokens when their password is changed.
We have noted that this finding is rarely presented as it really is only important on the most critical of applications. Picture an internal application that hooks into your servers and is very sensitive like an administration panel of some sort. That is where we want to be wary of concurrent sessions. This should not be an issue you see much on much less sensitive applications. But, in this situation the issue is quite simply that you can login from multiple locations, or otherwise have multiple sessions active at the same time. The recommendation here is to restrict a given user to a single session at one time. This makes a very obvious layer of security in alerting the user if someone else is trying to use the application as them by kicking them out. Additionally, this is important when integrity is king. If only a single session per user is allowed to perform any Create, Read, Update, Delete (CRUD) operations at a time then you remove many potential integrity problems that could be caused by hung session and strange browser errors.
An oldie but a goodie! Session fixation involves the ability for an attacker to set a pre-determined session cookie, or abuse a session cookie that is not changed upon logging in, that is then granted authorizations as the victim user when they authenticate. Session fixation has largely been wiped out, but on rare occasion I have still seen it in play with obscure libraries. Most modern frameworks handle the entire session management process for you and do not fall victim to this vulnerability. If you do have a finding on this it may not come as a low, but in the event it does I highly recommend fixing it anyways! To fix this issue simply change the session ID upon the user logging in and do not actually grant authorization under the session ID they POSTed their credentials with.
We recently worked a web app test that involved a modern front end using REACT, but the front-end isn’t important here, which handled all of our requests to the actual API endpoints that powered the web application. Upon logging in two JWTs were set. One we will call auth and the other refresh. These two tokens were then used throughout normal use to both authorize actions, and on occasion refresh the auth token as it reached its rather short timeout.
In this example neither of these tokens were invalidated upon logout, but it wasn’t all that severe because the auth token had a 10 minute lifespan. The refresh token on the other hand was valid for 24 hours. This was a problem, because the refresh endpoint would also accept this token after logout and this excessive timeout in addition to not invalidating on logout meant that an attacker could renew sessions for 24 hours.
As an aside, refresh tokens are gaining popularity because they offer a great user experience without storing actual credentials. Secure storage of these refresh tokens is paramount if this practice is used.
Overall, many of the issues we discussed involve a simple configuration change in modern frameworks. Like changing your timeout is not usually a difficult task. If you want to learn even more about session management there is a great cheat sheet from OWASP available here: Session_Management_Cheat_Sheet
Are you looking for a security assessment for your network or applications? Send us an email at info@mccormackcyber.com