Secure coding techniques in ASP.NET - Part 2

balaji
By balaji

April 17, 2010

In continuation of the secure coding techniques in ASP.NET series we will be talking about another programmatic implementation of the anti-CSRF token, and protection against session fixation attacks.

In continuation of the secure coding techniques in ASP.NET series we will be talking about another programmatic implementation of the anti-CSRF token, and protection against session fixation attacks.

Anti-CSRF token implementation

If we want to implement Anti-CSRF tokens for critical sections of the website only, then the following implementation would be useful. The key to any anti-csrf token implementation, is that the

  • Token set by the server should be random and unique, and
  • Server should have some way of "remembering" the token and verifying it whenever a Form is submitted.

ASP.NET provides the Guid class which implements a NewGuid method to generate unique 128-bit integer. This generates a unique string that is never duplicated. According to MSDN: "There is a very low probability that the value of the new Guid is all zeroes or equal to any other Guid."

So we get our random and unique token. It will be difficult for the attacker to guess this token.

//Create a unique and random string
string CSRF_Token = System.Guid.NewGuid().ToString();

The server can "remember" the token using session variables, however care must be taken when multiple forms implement CSRF tokens, and use session variables. Session variables have global scope, therefore the session variable used to store the CSRF token on each page where it is implemented should be unique. Otherwise, the session variable set in one page will be easily overwritten when the same user access another form simultaneously.

Uniqueness of session variables can be achieved by tying the session variable to the page, by following a nomenclature: <page_name>_ID.

//First get the current page name
string page_name = System.IO.Path.GetFileName(System.
Web.HttpContext.Current.Request.Url.AbsolutePath);
//Create the name of the session variable for the current page
string page_token = page_name + "_ID";
// Assign the CSRF token to the session variable.
Session[page_token] = CSRF_Token;
//Finally assign the CSRF token to a hidden field
HiddenField1.value = CSRF_Token;

All the above code should be executed when the first request for the form is made. We can use the IsPostback Property of the ASP.NET page to check if the page has been requested for the first time - Page_Load method.

Now when the form is submitted, the hidden variable's value is compared to the CSRF token session variable for that page. If the values are different, the user is logged out. If the values are same, processing occurs normally. Since, it won't be possible for an adversary to guess the GUID string value; this implementation would prevent CSRF attacks for all plausible scenario.

The above verification can be done in the Button Click code shown as below:

protected void Button1_Click(object sender, EventArgs e)
{
//First build the session variable name
string Page_Token = System.IO.Path.GetFileName(System.
Web.HttpContext.Current.Request.Url.AbsolutePath)+"_ID";
//Compare the hidden field value with the session variable of the page.
if (HiddenField1.Value.ToString() != Session[Page_Token].ToString())
{
Session.Abandon();
Session.Clear();
Response.Redirect("default.aspx");
}
else
{ //Do Processing }
}

Protection against session fixation attacks

Those who have worked with ASP.NET applications and use session variables to identify authenticated users would be aware that the ASPNET_SessionID cookie is set by the server whenever a user accesses any page of the website that uses ASP.NET. So when the login page is first accessed the ASP.NET_SessionID cookie is set at the browser. For all subsequent requests the browser and server use this cookie value. Even after authentication is successful and the application sets session variables the ASP.NET_SessionID value does not change.

This results in the possibility of session fixation attack, where a local adversary can potentially fix a victim's session by accessing the login page. If the victim uses that login page to authenticate to the application, then the adversary may be able to hijack the victim's authenticated session, since he knows the ASP.NET_SessionID that was set at the login page.

In order to mitigate this vulnerability, the login page should implement code that would invalidate all session variables and force the application to set a new ASP.NET_SessionID on successful login.

At the login page Page_Load event we should implement the code that invalidates session.

//Destroy the  current session variables at server
Session.Abandon();
//Set a blank ASP.NET_SessionID cookie if the request
//is the first request to the login page.
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));

The response for login page will have a response header like:

HTTP/1.x 200 OK
Server: ASP.NET Development Server/8.0.0.0
Date: Sat, 10 Oct 2009 11:52:10 GMT
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=; path=/
Cache-Control: private

The user will access the login page and submit the username and password to the application.

The HTTP POST request to submit the login credentials will look like below.

POST /cooki_change_on_login/login.aspx HTTP/1.1
Host: localhost:1795
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:1795/cooki_change_on_login/Default.aspx
Cookie: ASP.NET_SessionId=
Content-Type: application/x-www-form-urlencoded
Content-Length: 201
__VIEWSTATE=%2FwEPDwUKMTYzNzQ1&UserID=bob&Password=1234&Button1=Submit

On successful authentication the user will re-directed to the home page of the application after appropriate session variables set.

Session["isAuthenticated"] = True;
Session["user"] = user;
Response.Redirect("home.aspx");

The Web server, on seeing that the session cookie value was set to null in the request, will set an appropriate session cookie value in the HTTP 302 response.

HTTP/1.x 302 Found
Server: ASP.NET Development Server/8.0.0.0
Date: Sat, 10 Oct 2009 11:52:32 GMT
X-AspNet-Version: 2.0.50727
Location: /cooki_change_on_login/home.aspx
Set-Cookie: ASP.NET_SessionId=10g5o4zjkmbd2i552d5j3255; path=/;
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 154
Connection: Close

Thus now the authenticated user accesses the application with a newly set ASP.NETSessionid cookie.


Tags: Best Practices

About

balaji