Sunday, April 17, 2011

Cookieless Session State Asp.net

Cookieless Session State Asp.net

ASP.NET Session State by default uses a cookie to store session ID. Session ID is a unique string, used to recognize individual visitor between visits. But, if client's web browser doesn't support cookies or visitor has disabled cookies in web browser's settings, ASP.NET can't store session id on client's machine. In this case, new session will be created for every request. This behavior is useless because we can't remember information for certain visitor between two requests. We can say that, by default, sessions can't work if browser doesn't support cookies.

ASP.NET sessions without cookies (cookieless session)

ASP.NET supports sessions without cookies, known as cookieless sessions. As an alternative, ASP.NET can embed session id inside of page URL. On this way, all page links will contain session id string. When visitor clicks on some of these links, ASP.NET will read session id from page URL, so we don't need cookies support to have functional sessions.

To enable cookieless sessions, add cookieless="true", or cookieless="UseUri" (both options have the same meaning) inside sessionState tag in web.config file, like this:

<sessionState cookieless="true" />

SessionState element in web.config file is located inside <configuration>, <system.web> elements. Default behavior for sessions with cookies could be set with cookieless="false". Since it is already specified in machine.config file and inherited to all ASP.NET applications on server, you don't need any configuration change if you use cookie sessions.

As a result of cookieless="true", session id will be embedded in all page URLs. The drawback is that you'll end up with ugly URLs, which are not so good for SEO (search engine optimization) and visitor definitely will not remember it. Here is an example URL of website which uses ASP.NET cookieless sessions:

http://mappoint.msn.com/(22b5c4zyybphaw2mt3hjni2n)/Home.aspx

Bolded part represents session id, which is used to recognize a visitor. Possible problem is that URL will be different for every visitor and every visit, because they will have different session identities. If user just copy URL and paste it somewhere while recommending your website, he or she will send its session id too. This could be potential security risk if session is not expired yet. Also, search engines will consider any of these links as separate page. This will divide page ranking and decrease position of your page in search engine results.

Cookieless session and absolute URLs problem

There is a problem with absolute URLs if Cookieless session is used (e.g. URLs which starts with http://, https:// etc.), and with URLs which starts with slash character "/". So, you can't use links like /products/Product1.aspx anymore. If you place absolute link on your page, ASP.NET will not embed session id in it. If visitor clicks on link without current session id, he or she will get new session with new session id. Previous session and its data will be lost. With every next click on absolute links, visitor will get new session each time. On this way session becomes useless, because it cant remember user's data between two requests. So, easiest solution is to simply forget links with absolute URLs on cookieless website.

Other option is to embed session id into absolute URLs by using Response.ApplyAppPathModifier method. This could be useful, for example if we read and display a list of absolute URLs from database, or perform redirection from http:// to https:// etc. Here is a simple example of modification of absolute URL. Resulting URL will contain embedded current session id:

<a id="Hyperlink1" runat="server" href='<% =Response.ApplyAppPathModifier("http://mysite.com/Some-Absolute-Link.aspx"); %>' >Absolute link with cookieless session example</a>

In the other hand, absolute links are pretty useful for static files like images, .js, .css, .zip files etc.

Cookieless session and links to images, JavaScript files, CSS files etc.

When cookieless="true" is used, every relative link will be rewritten to embed session id. That includes links to files like images, JavaScript files, CSS files, PDF files, ZIP files for download etc.

In most cases, you don't need session id embedded inside of these links. Embedded session id inside of links to images and other similar files could cause cache problems.

For every new visit, visitor will get different session id. Thus, same image will always have different URL. Different URL means different image for web browser. If you check "Temporary Internet Files" in Internet Explorer or some other browser, notice that same image is saved many times. Actually, it is saved again each time you visit cookieless website. This could be a problem, especially on high traffic websites. In this case, cookieless session could increase bandwidth costs and slow down page loading, since same files must be downloaded multiple times and stored separately.

As a simple solution, you can use absolute links for images, JavaScript, CSS, PDF and similar files and avoid session id issue on this way.

ASP.NET cookieless options

ASP.NET offers six different options for cookieless attribute.

UseCookies - This is default option, set in machine.config file. ASP.NET website will use cookies to store session id, even if client doesn't support them. In case that client refuse to save cookie, session data will be lost and new session is created for each request. Thus, clients without cookie support can't use web application.

false - has same meaning as UseCookies.

UseUri - Website will embed session id inside of all relative URLs. ASP.NET Session State will never use cookies, even if client browser supports them. Sessions will work on each client, but could be less secure than session with cookie.

true - same as UseUri.

UseDeviceProfile - ASP.NET will check client if it's capable to support cookies. If client can support cookies, cookie will be used to store session id. Notice that this method just checks browser's features, but it doesn't consider an option that user is manually disabled cookies in browser. If web browser application supports cookies but user is disabled them, session will not work.

AutoDetect - ASP.NET will automatically detect if client supports cookies or not. If client supports cookies, website will use a cookie as storage for session id. If client doesn't support cookies, ASP.NET will embed session id in page URL. This looks as good compromise, although could cause problems with search engines.

Cookieless sessions and RegenerateExpiredSessionId parameter

To enable cookieless session, it is enough to set appropriate value for cookieless parameter. But, sessionState element contains RegenerateExpiredSessionId parameter which is important for security reasons. RegenerateExpiredSessionId could have two values:

True - Expired session ids can't be used again. If visitor comes to website using old session id, it will be replaced with new session id

False - If visitor uses old session id to visit website (e.g. through a bookmark, search engines, social networks etc.), website will create new session collection but session id will stay same.

For security reasons, especially with cookieless sessions, is better to always use RegenerateExpiredSessionId="True". On this way expired session id will not be used for new session, to avoid that different visitors have same session id.

SEO (Search Engine Optimization) and cookieless sessions

Search engines like Google could provide a lot of visits to website. Everything begins when Googlebot, or some others' search bot application, make requests to website to load its content and save it to their database for further analyze. Saved data are then provided for search on search engine, and possibly listed in search results.

Important issue when working with cookieless sessions is duplicate content. Let's suppose that you have one page with unique content. Each time when search bot reads that page, ASP.NET will assign different session id to it. Different session id means different URLs on page. So, instead to see your page as one page with original content, search bot could consider that you have a lot of different pages with same content. That is not good for search engine optimization, because your page will divide its ranking and be shown on the bottom of search results where no one clicks.

The solution for this could be to use cookieless="UseDeviceProfile" and then add new browser profile for each search bot inside <browsers> element in web.config. For example, if user agent string contains word "Googlebot", browser profile will tell ASP.NET that Googlebot supports cookies. On this way, session id will not use cookies when Google bot comes. Of course, we know that Googlebot doesn't support cookies, so this sounds more like hack than recommended nice looking solution. But, it will work and you can add new browser profile for any problematic search bot. Notice that UseDeviceProfile only looks on browser capabilities, thus on this way you are losing visitors with capable browsers, but who manually disabled cookies.

One more potential SEO problem with cookieless sessions is HTTP 302 redirect. When, search bot makes requests to some domain which uses cookieless sessions, ASP.NET will redirect visitor to other link with session id embedded. During this process, ASP.NET will use HTTP 302 Found message. Code 302 could have two meanings: 303 or 307. "303 See Other" means that correct content is found on different URL. 307 response represents temporary redirect. So, correct status code should be 307, temporary redirect, because in that case main link without session id is considered as the correct one. Unfortunately, bad architecture of ASP.NET cookieless session redirects using vague 302 message which is more often perceived as 303, than as 307. The consequence is that search bots usually save URL with session id embedded and even worse, see different pages each time when crawl through website.

Fortunately, main search engines learned how to deal with session variables, so now the problem is not so big as before. Still, clean URLs with keywords only will always rank better in search results, thus I can say that cookieless sessions generally are not good for SEO.

Security issues and cookieless session

Main security problem when working with sessions is a possibility that malicious user will find out others' session id. If two users share same session id, they share same session variables too and website is considering them as one visitor. This could be a security risk if session is used for any private or sensitive data, or to allow access to restricted areas of web site. When cookies are used, session id can be protected using SSL and by marking a cookie as secure. But, in case of cookieless session, session id is part of URL and is much more vulnerable.

Attacker could use network monitoring tool to see requested URLs. Because session id is part of URL, if you know requested URL you know session id too. Also, if malicious user get access to recent web server's logs, it is possible to read recent requested URLs and visit website with still active session.

On more problem is e-mail, social network or instant messenger communication. Pretty innocent question, as "Can you send me link to that page please?" could be huge security risk. Visitor could copy link from address bar and send it to someone through an email, some instant messenger, like AIM, Windows Live Messenger, Skype etc., or through social networks like Facebook. When other person use received link to open website, he or she will share same session as sender, and possibly see private data or have access to restricted area of web site.

Search bots generally don't accept cookies. That means that bots will get cookieless session and see URLs with embedded session id. If these URLs appear in search results, they will still contain that session id. So, imagine that first visitor comes to your website from Google search. Website will read session id from given URL. Then, after few minutes, second visitor comes using the same link. Now these two, and every next visitor that comes from search engine will share same session id, and same session variables and all of them will be considered as single visitor! This could make sessions useless and also be potential security risk. To solve this problem, always set RegenerateExpiredSessionId="True" when working with cookieless session. When RegenerateExpiredSessionId="True" and some visitor comes through an URL that contains expired session id, ASP.NET will assign new unique session id.

Since session id is so exposed when cookieless sessions are used, to increase security you can check some other information from visitor, like information from Request.Browser properties. Checking of IP address is also an option, but notice that some Internet service providers change IP address during the single visit. In cases like this, often you still can check first two numbers of IP address because they usually stay the same.

Notice that visitors usually disable cookies for security reasons. In case of cookieless sesions, ironically, visitor become much more insecure than if session with cookie is used.

Menu and TreeView control when cookieless session is used

Menu and TreeView controls are standard controls used for site navigation. Keep in mind that these controls will not automatically add session ids. For example, very common scenario is to bind Menu or TreeView control to SiteMapDataSource control. It looks logical that resulting links on page will have session id embedded. But, Menu or TreeView control will display just simple absolute links without ids.

To resolve this, we need to use Response.ApplyAppPathModifier method again. In this case, we'll use MenuItemDataBound or TreeNodeDataBound events respectively:

[ C# ]

// Cookieless sessions with Menu control
protected void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)
{
// Embeds session id
   e.Item.NavigateUrl = Response.ApplyAppPathModifier(e.Item.NavigateUrl);
}
// Cookieless sessions with TreeView control
protected void TreeView1_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
// Embeds session id
   e.Node.NavigateUrl = Response.ApplyAppPathModifier(e.Node.NavigateUrl);
}

[ VB.NET ]

' Cookieless sessions with Menu control
Protected Sub Menu1_MenuItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.MenuEventArgs) Handles Menu1.MenuItemDataBound
' Embeds session id
   e.Item.NavigateUrl = Response.ApplyAppPathModifier(e.Item.NavigateUrl)
End Sub
' Cookieless sessions with TreeView control
Protected Sub TreeView1_TreeNodeDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles TreeView1.TreeNodeDataBound
' Embeds session id
   e.Node.NavigateUrl = Response.ApplyAppPathModifier(e.Node.NavigateUrl)
End Sub

Now, all links in Menu or TreeView controls will have session ids embedded.

Session.IsCookieless property

You can check in run time if session is cookieless sessions or not. This is useful if you are creating an application that could be included as module on others' websites (e.g. forum, user support application etc.). In this case, you can't change settings in main web.config file, but you can check in code if session requires cookies but visitor is disabled them, and if needed redirect and inform visitor so he or she knows why application doesn't work. Example of using Session.IsCookieless property could look like this:

[ C# ]

if (Session.IsCookieless)
{
// Web application uses cookieless session
}
else
{
// Web application uses cookies to work with sessions
// If needed, inform visitor that cookies are required
}

[ VB.NET ]

If (Session.IsCookieless) Then
' Web application uses cookieless session
Else
' Web application uses cookies to work with sessions
' If needed, inform visitor that cookies are required
End If

Conclusion

HTTP is stateless protocol, which means that it doesn't provide a way to save information of same visitor between two requests. ASP.NET offers Session State as a method to resolve this problem. To find out more about other possible methods, check ASP.NET Session State Alternatives tutorial. In general, to save visitor's state when using stateless protocol, you can place id inside of page's HTML or as part of URL. In HTML, there are two options: <head> or <body> tags. Cookies are part of <head> tag, but this is automatically managed by web browser.

ASP.NET ViewState stores information inside of <body> tag, as hidden field. This works nice, but the problem is that this method can only work with POST, and can't work if GET method is used.

Third, and last option is to store information inside of page URL, and that is how cookieless session work. Be aware that some mobile devices can't read format of cookieless URLs with parentheses, and cookieless sessions could cause problems with some URL rewriting modules.

If you have pure HTML pages, there is a problem to share POST data between HTML form and ASP.NET web form. When cookieless ASP.NET form is posted, it contains information about session id too. But, if you make POST on HTML form, it will not contain session id and new session will be created. In that case, data of previous session will be lost. The solution could be to embed session id to link in form's action attribute. You can do that using Response.ApplyAppPathModifier method like in previous examples.

Limitations

The principal limitation of this feature is the limited amount of data that can be stored in the URL. This feature is not targeted at common browsers such as IE, since these do support cookies and do not require this feature. The browsers that do not support cookies are the ones found on mobile devices (such as phones), and these browsers typically severely limit the size of the URL they support. So, be careful when you use this feature—try to make sure that the cookieless string generated by your application is small.

A second limitation on the size comes on the Windows 2003 platform. A (configurable) setting on the Windows Networking layer requires that each segment of the URL be less than 256 chars in length. Since the entire cookieless string goes into 1 segment, it must be less than 256 chars. (A segment of the URL is the portion of the URL between two forward slashes ('/')).

8 comments:

  1. This is a nice article..
    Its easy to understand ..
    And this article is using to learn something about it..

    c#, dot.net, php tutorial, Ms sql server

    Thanks a lot..!
    ri80

    ReplyDelete
  2. This is a nice article, thanks for sharing. Also have a look at these articles which is related to this one:-

    How to implement Cookieless Session in ASP. Net

    Regards,

    Zeeshan Umar

    ReplyDelete
  3. The post is absolutely fantastic! Lots of great information and inspiration, both of which we all need. I will bookmark this site for future viewing. Thanks for sharing.android developer

    ReplyDelete
  4. As when i read your article, it seems to be really quite interesting. Good concepts chosen. keep posting more and more..
    seo forums

    ReplyDelete
  5. Very Nice Article Mr. Farrukh. Could you please let me know, how remember me option in asp.net could still work with cookie disabled browsers..

    ReplyDelete
  6. you are in reality a good webmaster. The web site loading pace is incredible. It seems that you are doing any distinctive trick. Also, The contents are masterwork. you’ve performed a excellent job on this topic!

    Samsung galaxy note 2 / note II cases

    ReplyDelete

PDF Arabic watermark using MVC and iTextSharp

PDF full page Arabic watermark using MVC and iTextSharp Download :  Source Code Most of the time we have requirement to  gen...