Updated 20 days ago | GitHub

Session Fixation

Session fixation is an attack where the attacker provides a user with a valid session identifier. It is like the opposite of session hijacking. Instead of stealing the user’s session ID (so that both the attacker and user are sharing a session), the attacker gives the user a session ID to use (so that both the attacker and the user are sharing a session). Both attacks are used for the same purposes–the attacker gains an authenticated session which can access restricted information and actions.

In a session fixation attack, the attacker creates a session with the target website, but they do not bother logging in. They just need to get a session created and know the session ID. Next, the attacker tricks a user into using the attacker’s session ID. (More on how this is possible in a moment.) Then when the user next logs in to the website, unaware that they are using someone else’s session ID, the website will bestow the attacker’s session with the authentication. Now, the attacker can visit the access-restricted pages using the same session.

The simplest session fixation attacks rely on session IDs being accepted from URLs or form data. If a website allows a session ID in a URL, then it is simply a matter of getting a user to click on that link.

http://yoursite.com/login.php?PHPSESSID=qvidf3pweno6c12whk3hk26oxs0hjke0

The link does not even need to go to a login page or an access-restricted page. Any page on the website’s domain will work, as long as the website attaches the attacker’s session ID to the user.

It has become uncommon to maintain session IDs in URL strings, in part due to session fixation. For example, in PHP, default configurations were changed in 2002 to make it more difficult to turn on this option.

However, this does not mean that session fixation is not possible now. It is still possible if an attacker has the ability to set the user’s browser cookie to their session ID. Most often this is done using Cross-Site Scripting (XSS).

http://yoursite.com/page.php?q=<script>document.cookie="PHPSESSID=qvidf3pweno6c12whk3hk26oxs0hjke0";</script>

A more sophisticated attack could set the cookie data in other ways, such as by altering the response data that the user receives. This could be done as a Man in the Middle attack. The response is allowed to include a Set-Cookie directive.

Set-Cookie: PHPSESSID=qvidf3pweno6c12whk3hk26oxs0hjke0

Session Fixation Preventions

Never accept session identifiers as GET or POST variables. Only accept session identifiers from cookies. This removes the easiest way to set a session ID.

Another mitigation is to use HttpOnly cookies, which prevent JavaScript from reading session cookies. This blocks one Cross-Site Scripting (XSS)-based session-theft path, but HttpOnly by itself does not prevent session fixation — an attacker can still fix a session ID through other vectors (for example, a Set-Cookie header injected by a man-in-the-middle, or a vulnerable subdomain setting a cookie on the parent domain). The primary defense, covered below, is to regenerate the session identifier after a successful login. Pairing the session cookie with Secure, SameSite=Lax or Strict, and the __Host- prefix further reduces these vectors.

// In php.ini configuration
session.use_only_cookies = 1
session.cookie_httponly = 1

These values can be set in the php.ini file or (since PHP 7.0) as options passed to session_start(). (See cookie and session options)


Regenerating session identifiers

The single best defense against session fixations is to regenerate session identifiers after login. Regenerating a session ID gives the user a fresh session ID, instead of using the attacker-provided session ID. When the user is authenticated, their authorization will be stored on the new session ID. The attacker will have the old one and it will not have been granted access.

<?php
 function after_successful_login() {
   session_regenerate_id();
   $_SESSION['logged_in'] = true;
   $_SESSION['last_login'] = time();
 }
?>