Tuesday, February 22, 2005

ASP.NET Session Cookies and Authentication Cookies

In previous blog I briefly mentioned the Session cookie and the Authentication Cookie. How do they work?

First let's look at the Session in ASP.NET. ASP.NET Session is a state management mechanism that maintains session data inside the server for a unique user interacting with the server for a period of time. For example, you can pull a user profile data from database during user's first visit and store it into Session, then for the next requests from the same user you can retrieve the profile data directly from Session without bothering database:

User currentUser = Session["UserProfile"] as User;
if (currentUser == null)
{

currentUser = UserService.GetUserById(id);
Session[
"UserProfile"] = currentUser;
}


The Session data are stored in memory by default. But you have option to store Session data in a dedicated machine, in database, or use your you own session provider. This is important in a web farm environment.

How do ASP.NET web server identify a user and retrieve its Session data? ASP.NET uses a 120 bit identifier (Session ID) to track each session. When the user first talks to the server, the Session cookie is empty and the server will create a new Session ID and set to Session cookie which will be kept in user's browser store (non-persistent cookie). When the user talks the server again, ASP.NET looks on to Session ID and retrieves corresponding data. You can see the Session cookie using a traffic monitor tool such as Fiddler :

Cookie: ASP.NET_SessionId=ezdpwa55i5xo41rbp5bfbv55;

Now let's discuss the Authentication and Authentication cookie. Authentication is a mechanism to obtain a user's identity by validating its credential against the authority such as Active Directory or LDAP. By default ASP.NET supports Windows Authentication, Passpart Authentication, and Forms Authentication. In short, Windows Authentication is managed by IIS, Passport Authentication is handled by a web-based and centralized store control by Microsoft, and Forms Authentication is the only one that is able to check user credentials stored in a file or in a custom database. Authentication cookie is used in all three scenarios, but we only cover Forms Authentication cookie here.

With Forms Authentication, usually you create a login form with the logic to validate a user against credential store. If authentication fails then the user will be treated as anonymous user and granted limited permssion. If authentication succeeds, the server will create a Forms Authentication ticket and add the ticket in Authenticaiton cookie. This is usually done by:

FormsAuthentication.SetAuthCookie(userName, false);

Or

FormsAuthentication.RedirectFromLoginPage(userName, false);


The second parameter in above two methods sets the Authentication cookie to be non-persistent or persistent.

For security consideration, the Forms Authentication ticket is encrypted and signed using server's Machine.config configuration before saving to Authentication cookie. The default encryption algorithm is 3DES. You will see the real Authentication cookie like:

Cookie: .ASPXAUTH=5D49D0CFCC287EE624F53A0FFC51F436C098E90D6345ACC06BF249661725E004E403880ACEA9F069A221C2D4893D5BBDDA2AFE4A63D17DC04;


Because different machines have different encryption/decryption keys, the same Authentication cookie won't be able to be decrypted in all machines inside a web farm. To resolve this problem, you have to explicitly specify the values for "validationKey" and "decryptionKey" attributes in the section of your application’s web.config file in each machine cross the web farm, so all machines will use the same encryption/decryption keys.

(2006/03 updated) The same encryption/decryption keys are used to handled the ViewState for ASP.NET pages. You have to do the same configuration update if you have a web farm, otherwise you will get a server error:

Saturday, February 12, 2005

ASP.NET Cookies

A cookie is a small piece of data that is created in the server and stored in a client's web browser. Cookies are part of the request data that sent to the server. And server are able to retrieve or update cookies.

Cookie is used in ASP.NET to do the authentication and session tracing. Cookie can be easily manipulated in your ASP.NET web application, such as storing user preferences. It's a good practice to only store small piece of data inside cookie because browsers have cookie size limit. For example, IE has 4K of maximum size of cookie, and only allows 20 cookies per domain name.

To read a cookie, you get the HttpCookie collection from the Request object:
HttpCookie cookie = Request.Cookies["MyCookie"]; // Or Request.Cookies[0]
string cookieName = cookie.Name; // = "MyCookie"
string cookieValue = cookie.Value;
To set or update a cookie:
HttpCookie cookie = new HttpCookie("MyCookie");
cookie.Value = "My Value";
Response.Cookies.Add(aCookie);
Or simply:
Response.Cookies["MyCookie"].Value = "My Value";
To delete a Cookie, you have to update the cookie with expiration defined before current time:
Response.Cookies["MyCookie"].Expires = DateTime.Now.AddDays(-1);
Cookie with expiration time tells browser to remove the cookie when it's expired. A cookie without expired time is called non-persistent cookie because it won't store in user's hard disk, and the cookie is discarded when browser is closed. By default, Session cookie in ASP.NET is non-persistent cookie, while authentication cookie is persistent cookie.

Domain is another property you can set for a cookie. You may have a website of http://www.mysite.com and have a subdomain of http://sales.mysite.com. If you want to share the cookie in these two domains then you should do:
cookie.Domain = "mysite.com";
You can also limit the cookie to a folder in your application by setting cookie's Path property. For example, you want to have a cookie only available in http://www.mysite.com/Application1 and another cookie only available for http://www.mysite.com/Applicaiton2:
cookie1.Path = "/Application1";
cookie2.Path = "/Application2";
You can store one value in a cookie as described above. You can also store multiple name-value pairs in a single cookie:
Response.Cookies["MyCookie"]["Name1"] = "value1";
Response.Cookies["MyCookie"]["Name2"] = "value2";
To get a multi-value cookie:
string cookieValue1 = Request.Cookies["MyCookie"]["Name1"];
string cookieValue2 = Request.Cookies["MyCookie"]["Name2"];
Just for your curiosity, the multi-value cookie transferred between browser and server is something like:

Cookie: MyCookie=Name1=value1|Name2=value2;