Skip to main content

Authentication ASP.NET_SessionId (Session) along with AuthToken (GUID) cookie

Authentication ASP.NET_SessionID (Session) along with AuthToken (GUID) cookie

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

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.

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

<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

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 theTextBoxes' value.
On click of the Logout button, we call the Session.Clear()Session.Abandon() andSession.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.

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, theASP.NET_SessionId cookie exists.
ASP.NET_SessionId cookie even if user is logged out

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

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 AuthTokencookie 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 arenot 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 


Comments

Popular posts from this blog

PNR Status by web Scraping Method (ASP.NET) C#

To Get the PNR Status by web Scraping Method Steps to Execute the Function Step 1 : Add the below method in your Form and Pass the PNR Number arguement public string GetPNRStatus( string sPNR) { string URI = "http://www.indianrail.gov.in/cgi_bin/inet_pnrstat_cgi.cgi" ; string Parameters = Uri .EscapeUriString( "lccp_pnrno1=" +sPNR+ "&amp;submitpnr=Get Status" ); System.Net. HttpWebRequest req = ( HttpWebRequest )System.Net. WebRequest .Create(URI); //HTTP POST Headers req.ContentType = "application/x-www-form-urlencoded" ; req.Host = "www.indianrail.gov.in" ; //You can use your own user-agent. req.UserAgent = "Mozilla/5.0 (compatible; MSIE 7.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0) DELL;Venue Pro" ; req.Headers.Add( HttpRequestHeader .AcceptLanguage, "en-us,en;q=0.5" ); req.Headers.Add( HttpRequestHeader .AcceptCharset, "ISO-8859-1,utf-8;q=
C# HttpClient tutorial C# HttpClient tutorial shows how to create HTTP requests with HttpClient in C#. In the examples, we create simple GET and POST requests. The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, hypermedia information systems. HTTP is the foundation of data communication for the World Wide Web. HttpClient  is a base class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI. C# HttpClient status code HTTP response status codes indicate whether a specific HTTP request has been successfully completed. Responses are grouped in five classes: Informational responses (100–199) Successful responses (200–299) Redirects (300–399) Client errors (400–499) Server errors (500–599) Program.cs using System; using System.Net.Http; using System.Threading.Tasks; namespace HttpClientStatus { class Program { static async Task Main(string[] args) { using var client = new

SonarQube Configuration For .NET Core Web API

When multiple developers are working on the same project, it's good to have a code review. SonarQube is a tool through which we can evaluate our code. Here, for demo purposes, we are going to evaluate the web API which is built on .NET Core. Let's see step by step implementation. In order to run SonarQube, we need to install JAVA in our local system.   Refer to the below link to download JAVA installer and install JAVA. https://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html Configure the 'PATH' system variable under environment variables Go to Control Panel > System > Advanced System Settings, it will open the System Properties window. Click on the "Environment Variables" button. Click on the "View" button under User Variables. Give the variable name as 'JAVA_HOME'. The variable value will be your JDK path where you installed JAVA. Select path variable under system variable and click o