Security on websites is based on session management. When a user connects to a secure website, they present credentials that testify to their identity, usually in the form of a username and password. Because the HTTP protocol is “stateless,” the web server has no way of knowing that a particular user has already logged in as they browse from page to page. Session management allows the web-based system to create a ‘session’ so that the user will not have to re-authenticate every time they wish to perform a new action, or browse to a new page.
In essence, session management ensures that the client currently connected is the same person who originally logged in. Unfortunately however, sessions are an obvious target for a malicious user, because they may be able to get access to a web server without needing to authenticate.
A typical scenario would involve a user logging on to an online service. Once the user is authenticated, the web server presents this user with a “session id.” This session ID is stored by the browser and is presented wherever authentication is necessary. This avoids repeating the login/password process over and over. It all happens in the background and is transparent to the user, making the browsing experience much more pleasant in general. Imagine having to enter your username and password every time you browsed to a new page!
The session ID itself is simply a string of characters or numbers. The server remembers that the session ID (SID) was given to the user and allows access when it is presented. As a result, the Session ID is of great value and malicious users have, for years, searched for ways to compromise it and use it to circumvent authentication mechanisms. Session Management is all about protecting this session ID, and in modern day interactive web applications this becomes critical.
So how to get your hands on a Session ID? There are a number of techniques attackers use to compromise a Session ID. The most obvious is to attack the server. The server often stores the session ID somewhere, and more worryingly, the server sometimes stores the session ID in a world-readable location. For example, PHP stores its session variables in the temporary /tmp directory on Unix. This location is world-readable, meaning that any user on that system can easily view the session IDs with basic utilities that are part of the Unix API. This is serious risk, particularly on shared hosts since many users will be active on the system. This issue has since been addressed but it is just one example.
Another method is to attack the client. Microsoft Internet Explorer, for example, has had numerous flaws that allowed web sites to read cookies (often used to store the Session ID) to which they did not belong. Ideally, only the site that created the cookie should have access to it. Unfortunately, this is not always the case, and there are many instances of cookies being accessible to anyone. On top of this, a browser’s cache is often accessible to anyone with access to that computer. It may be a hacker who has compromised the computer using some other attack, or a publicly accessible computer in an Internet cafÃ© or kiosk. Either way, a cookie persistently stored in the browser cache is a tempting target.
Unencrypted transmissions are all too common and allow communication to be observed by an attacker. Unless the HTTPS protocol is used, a Session ID could be intercepted in transit and re-used. In fact, it is possible to mark cookies as ‘secure’ so they will only be transmitted over HTTPS. This is something I have rarely seen developers do. Such a simple thing can go such a long way.
Another way to that is used to compromise a Session ID is to attempt to predict it. Prediction occurs when an attacker realises that a pattern exists between session IDs. For example, some web based systems increment the session ID each time a user logs on. Knowing one session ID allows malicious users to identify the previous and next ones. Others use a brute force attack. This is a simple yet potentially effective method for determining a session identifier. A brute force attack occurs when a malicious user repeatedly tries numerous session identifiers until they happen upon a valid one. Although it is not complicated, it can be highly effective.
So what can you do to mitigate these attacks?
1. Always use strong encryption during transmission. Failure to encrypt the session identifier could render the online system insecure. In addition, for cookie based sessions, set the SSL-only attribute to “true” for a little added security. This will reduce the chance that an XSS attack could capture the session ID because the pages on the unencrypted section of the site will not be able to read the cookie.
2. Expire sessions quickly. Force the user to log out after a short period of inactivity. This way, an abandoned session will only be live for a short duration and thus will reduce the chance that an attacker could happen upon an active session. It is also wise to avoid persistent logins. Persistent logins typically leave a session identifier (or worse, login and password information) in a cookie that resides in the user’s cache. This substantially increases the opportunity that an attacker has to get a valid SID.
3. Never make the Session ID viewable. This is a major problem with the GET method. GET variables are always present in the path string of the browser. Use the POST or cookie method instead or cycle the SID out with a new one frequently.
4. Always select a strong session identifier. Many attacks occur because the SID is too short or easily predicted. The identifier should be pseudo-random, retrieved from a seeded random number generator. For example, using a 32 character session identifier that contains the letters A-Z, a-z and 0-9 would have 2.27e57 possible IDs. This is equivalent to a 190 bit password. For example, using a 32 character session identifier that contains the letters A-Z, a-z and 0-9 is equivalent to a 190 bit password and is sufficiently strong for most web applications in use today.
5. Always double check critical operations. The server should re-authenticate anytime the user attempts to perform a critical operation. For example, if a user wishes to change their password, they should be forced to provide their original password first.
6. Always log out the user securely. Perform the logout operation such that the server state will inactivate the session as opposed to relying on the client to delete session information. Delete the session ID on logout. Some applications even force the browser to close down completely, thus ensuring stripping down the session and ensuring the deletion of the session ID.
7. Always prevent client-side page caching on pages that display sensitive information. Use HTTP to set the page expiration such that the page is not cached. Setting a page expiration that is in the past will cause the browser to discard the page contents from the cache.
8. Always require that users re-authenticate themselves after a specified period even if their session is still active. This will place an upper limit in the length of time that a successful session hijack can last. Otherwise, an attacker could keep a connection opened for an extremely long amount of time after a successful attack occurs.
9. It is possible to perform other kinds of sanity checking. For example, use web client string analysis, SSL client certificate checks and some level of IP address checking to provide basic assurance that clients are who they say they are.
All in all, web applications rely on good session management to stay secure. If you follow some of the steps outlined in this article and be aware of the risks, you are well on your way to leveraging the full benefits of web applications.