Disclaimer: I am Dopey

HTTP is stateless, which means that it provides no integrated way for a web server to maintain states throughout user’s requests.
To account for this, web apps can implement various kinds of session management were the server generates a session identifier (ID) at some early point in the user interaction, sends this ID to the user’s browser and ensures that this same ID will be sent back by the browser along with each subsequent request.
Therefore, session Ids become identification tokens for users and servers can use them to maintain session data, for example, variables, and create a session-like experience to the users and therefore a better user experience.


Session Ids are however attractive to attackers because once obtained they can basically hijack user’s identities.

There are quite a few different approaches attackers can attempt to hijack a session. Most of these focus on obtaining the user’s session ID through interception, prediction or brute-force attacks.

This article however will focus on an attack known as Session Fixation, which is the opposite of obtaining the user’s session ID, rather it deals with the attacker fixing the user’s Session ID before the user even logs on, thereby eliminating the need to obtain the user’s session Id afterwards.

Here’s how the timeline of the attack in an ASP.NET application plays out:

Timeline of Session Fixation Attack

Basically an attacker will attempt to set a victim’s session ID, in most cases before the victim logs in. When the victim logs in, that shared session will be initialised with the user’s data. Since the attacker is using the same session, they can go to a web page that displays data from the session, and they’ll see the victim’s data. Note that the attacker and the victim have different identities (authentication cookies), but they’re sharing the ASP.NET session.


Session Management In ASP.NET

Cookieless

Note: If you’re running with cookieless ASP.NET sessions (ID in URL) you are vulnerable to this attack unless you have put special checks in place to tie the session to the current user. The attacker just needs to trick the user into logging in to the target web server through a hyperlink they provide, for example, ...online.bigbank.com/(sessionId)/login.aspx.

OWASP recommend you: DO NOT use cookieless ASP.NET sessions.

As Troy Hunt states:

The problem with the cookieless approach is that URLs are just so easily distributable. Deep links within web apps are often shared simply by copying them out of the address bar and if the URL contains session information then there’s a real security risk.

This method, while feasible, is relatively impractical and comes with quite a risk of detection.

Cookies

Cookies are a widely used session ID transport mechanism, partly also due to their security in comparison to cookieless URL arguments and hidden form fields. However, cookies also provide an effective means of exploiting session fixation vulnerabilities.

Attack using cookies?

The attacker can choose among the three available methods for issuing a cookie to the browser:

  • Using a client-side script that sets a cookie on the browser.
  • Using the HTML tag with Set-Cookie attribute.
  • Using the Set-Cookie HTTP response header.

I’ll not go into the details of how these are done (google is your friend) rather I’ll focus next on how to mitigate the risk.


Prevention (Mitigation)

Prevent logins to a particular session

Session fixation means a user logs in to a session with an attacker-chosen ID, instead of having been issued a newly generated session ID by the server. To me there isn’t a good enough reason for web apps to allow this to happen. Web apps must ignore any session ID provided by the user’s browser at login and must always generate a new session to which the user will log in if successfully authenticated.

[HttpPost]
    public ActionResult Index(User model)
    {           
       if (service.Login(model.Email,model.Passwords))//Authenticate
            {                    
                AbandonSession();//Delete any existing sessions
                var newSessionId = CreateSessionId(HttpContext.Current); //Create a new SessionId
                SetSessionId(HttpContext.Current, newSessionId);

                return RedirectToAction("Index", "App");
            }
            else
            {
                ModelState.AddModelError("", "Email or Password Incorrect");
                return View(model);
            }
        }  
    }

public void AbandonSession()
    {
        Session.Clear();
        Session.Abandon();
        Session.RemoveAll();
        if (Request.Cookies["ASP.NET_SessionId"] != null)
        {
            Response.Cookies["ASP.NET_SessionId"].Value = string.Empty;
            Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddMonths(-20);
        }
    }

    private static string CreateSessionId(HttpContext httpContext)
    {
        var manager = new SessionIDManager();

        string newSessionId = manager.CreateSessionID(httpContext);

        return newSessionId;
    }

    public static void SetSessionId(HttpContext httpContext, string newSessionId)
    {
        var manager = new SessionIDManager();

        bool redirected;
        bool cookieAdded;

        manager.SaveSessionID(httpContext, newSessionId, out redirected, out cookieAdded);

    }

Stop attacker from obtaining a valid session ID

If possible, a web application on a strict system should only issue session IDs of newly generated sessions to users after they have successfully authenticated (as opposed to issuing them along with the login form). This means that an attacker who isn’t a legitimate user of the system will not be able to get a valid session ID and will therefore be unable to perform a session fixation attack.

Session Destruction

On Logout / Timeout or when the user closes the page/browser/tab the session should be ‘torn down’. This needs to be done on the server and not just on the browser by deleting the session cookie.

public ActionResult LogOut()
    {
        AbandonSession();

        return RedirectToAction("Index");
    }

For browser/tab close include the following Javascript layout file:

<script type="text/javascript">
    $(document).ready(function () {            

        window.onbeforeunload = function (e) {
            $.ajax({
                url: [email protected]("AbandonSession", "Home")'
            });
        };

        $(function () {
            $('a').not('#Logout').click(function () {
                window.onbeforeunload = null;
            });
            $('.btn').click(function () {
                window.onbeforeunload = null;
            });
        });

    });
</script>

Session Expiry

Absolute session timeouts prevent attackers from both maintaining a trap session as well as maintaining an already entered user’s session for a long period of time.

In Web.Config:

<system.web>
   <sessionState timeout="20"/>    
</system.web>

Conclusion

The session fixation vulnerability is extremely common in many session-enabled web apps. In my hunt for solutions I found it extremely difficult to find any “fix all” solution. It seems to be more about risk mitigation and making it as difficult as possible for a potential attacker. Hopefully this article will help you understand the vulnerability and perhaps help you prevent it.

Disclaimer again: I am Dopey