Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Session Fixation Vulnerability in ASP.NET

4.94/5 (24 votes)
14 Jun 2011CPOL4 min read 178.6K  
In this article, we are going to learn how to avoid the Session fixation vulnerability in ASP.NET.

Introduction

ASP.NET Session keeps track of the user by creating a cookie called ASP.NET_SessionId in the user browser. This cookie value is checked for every request to ensure that the data being served is specific to that user. In many applications, a Session variable is used to track the logged in user, i.e., if a session variable exists for that user, then the user is logged in, otherwise not.

Background - The Vulnerability

Whenever any data is saved into the Session, the ASP.NET_SessionId cookie is created in the user’s browser. Even if the user has logged out (means the Session data has been removed by calling the Session.Abandon() or Session.RemoveAll() or Session.Clear() method), this ASP.NET_SessionId cookie and its value is not deleted from the user browser. This legitimate cookie value can be used by the hijacker to hijack the user session by giving a link that exploits cross site scripting vulnerability to set this pre-defined cookie. When the user clicks this link and logs in, the user will have the same ASP.NET_SessionId cookie value that hijackers knows and he will also be able to browse the user account and will be able to access all the information pertaining to that user. This attack is called Session fixation vulnerability.

You can get hundreds of tips and tricks like this from my blog: .NET How to Tips and Tricks.

Let’s create a demo application that shows the existence of the ASP.NET_SessionId cookie even if the user has logged out and all Session data has been removed.

ASPX Page
ASP.NET
<fieldset>
    <legend>Login</legend>
    <p>Username : <asp:TextBox ID="txtU" runat="server" /> </p>
    <p>Password : <asp:TextBox ID="txtP" runat="server" /> </p>
    <p><asp:Button ID="btnSubmit" runat="server" 
            Text="Login" OnClick="LoginMe" />
    <asp:Label ID="lblMessage" runat="server" EnableViewState="false" />
    <asp:Button ID="btnLogout" runat="server" 
            Text="Logout" OnClick="LogoutMe" Visible="false" />
    </p>
</fieldset>

In the above code snippet, we have two TextBoxes, two Buttons, and a Label control.

Code-behind
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (Session["LoggedIn"] != null)
    {
        lblMessage.Text = "Congratulations !, you are logged in.";
        lblMessage.ForeColor = System.Drawing.Color.Green;
        btnLogout.Visible = true;
    }
    else
    {
        lblMessage.Text = "You are not logged in.";
        lblMessage.ForeColor = System.Drawing.Color.Red;
    }
}

protected void LoginMe(object sender, EventArgs e)
{
    // Check for Username and password (hard coded for this demo)
    if (txtU.Text.Trim().Equals("u") && txtP.Text.Trim().Equals("p"))
    {
        Session["LoggedIn"] = txtU.Text.Trim();
    }
    else
    {
        lblMessage.Text = "Wrong username or password";
    }
}

protected void LogoutMe(object sender, EventArgs e)
{
    Session.Clear();
    Session.Abandon();
    Session.RemoveAll();
}

On click of the Login button, the LoginMe method fires that creates Session[“LoggedIn”] after validating the TextBoxes' value.

On click of the Logout button, we call the Session.Clear(), Session.Abandon() and Session.RemoveAll() methods to ensure that the session variable is removed.

Output

The ASP.NET_SessionId cookie when user is logged in

Notice in the below image that when the user has logged in, an ASP.NET_SessionId cookie has been created.

Itfunda_1896_1.JPG

After clicking on Login, go back and refresh the page.

Now when we click on the Logout button, even if the Session has been abandoned / removed, the ASP.NET_SessionId cookie exists.

ASP.NET_SessionId cookie even if user is logged out

Itfunda_4103_2.JPG

After clicking on Login, go back and refresh the page.

How to fix this vulnerability

Simple fix

To avoid Session fixation vulnerability attacks, we can explicitly remove the ASP.NET_SessionId cookie in the Logout method.

Bullet proof fix

To bullet proof this attack, we can create another cookie (e.g., AuthCookie) with a unique value and the same value can be stored into the Session as well. On every page load, we can match this cookie value with the Session value; if both matches, then let the use enter the application otherwise redirect to the Login page.

In the Logout function, ensure that you are removing this new Cookie “AuthCookie” as well. To remove this cookie, simply set its expiration date time to a few months earlier than the current date time.

So my modified code-behind for this page looks like below:

Modified code-behind
C#
protected void Page_Load(object sender, EventArgs e)
{
    //NOTE: Keep this Session and Auth Cookie check
    //condition in your Master Page Page_Load event
    if (Session["LoggedIn"] != null && Session["AuthToken"] != null 
           && Request.Cookies["AuthToken"] != null)
    {
        if (!Session["AuthToken"].ToString().Equals(
                   Request.Cookies["AuthToken"].Value))
        {
            // redirect to the login page in real application
            lblMessage.Text = "You are not logged in.";
        }
        else
        {
            lblMessage.Text = "Congratulations !, you are logged in.";
            lblMessage.ForeColor = System.Drawing.Color.Green;
            btnLogout.Visible = true;
        }
    }
    else
    {
        lblMessage.Text = "You are not logged in.";
        lblMessage.ForeColor = System.Drawing.Color.Red;
    }
}

protected void LoginMe(object sender, EventArgs e)
{
    // Check for Username and password (hard coded for this demo)
    if (txtU.Text.Trim().Equals("u") && 
                  txtP.Text.Trim().Equals("p"))
    {
        Session["LoggedIn"] = txtU.Text.Trim();
        // createa a new GUID and save into the session
        string guid = Guid.NewGuid().ToString();
        Session["AuthToken"] = guid;
        // now create a new cookie with this guid value
        Response.Cookies.Add(new HttpCookie("AuthToken", guid));

    }
    else
    {
        lblMessage.Text = "Wrong username or password";
    }
}

protected void LogoutMe(object sender, EventArgs e)
{
    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);
    }

    if (Request.Cookies["AuthToken"] != null)
    {
        Response.Cookies["AuthToken"].Value = string.Empty;
        Response.Cookies["AuthToken"].Expires = DateTime.Now.AddMonths(-20);
    }
}

LoginMe method

First, let's focus on the LoginMe method that fires on the click of the Login button. In this method, after setting the normal Session variable, we create a GUID (a unique value and almost impossible to guess) and save it as a new Session variable called AuthToken. The same GUID is then saved into a cookie named AuthToken.

LogoutMe method

In the LogoutMe method, we first explicitly expire the ASP.NET_SessionId cookie to make sure that this cookie is removed from the browser when the user clicks on the Logout button, and after that, we expire the AuthToken cookie as well.

Page_Load event (In real time applications, keep this logic in the Master Page Page_Load method)

In the Page_Load event, we check for the normal LoggedIn session variable and along with that, we also check for the new Session variable called AuthToken and the new Cookie AuthToken. If all three of them are not null, then again we match the new Session variable AuthToken and the new Cookie AuthToken values. If both are not the same, then we write a failure message (in a real time application, redirect the user to the Login page).

This logic makes sure that even if the ASP.NET_SessionId cookie value is known to the hijacker, he will not be able to login to the application as we are checking for the new Session value with the new cookie that is created by us and their GUID value is created by us. A hijacker can know the Cookie value but he can’t know the Session value that is stored in the web server level, and as this AuthToken value changes every time the user logs in, the older value will not work and the hijacker will not be able to even guess this value. Unless the new Session (AuthToken) value and the new Cookie (AuthToken) are the same, no one will be able to login to the application.

Output

ASP.NET_SessionId along with AuthToken cookie

Itfunda_6193_3.JPG

Hope you find this article interesting, thanks for reading. Subscribe to my RSS feed to read more articles on a regular basis.

Originally posted here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)