Sunday, April 3, 2011

Cookieless Session State in ASP.NET without nasty URLs

Some of you have probably heard about the EU proposal that plans to end the internet as we know it on May 25th 2011. If you haven’t heard of it, David Naylor has made a nice little example of it’s consequences here. In essence most sites that use cookies will have to ask visitors to opt-in for every single cookie before using it. I’m very  much in favor of online privacy – yet it seems to me that this is a very poorly thought through directive. First of all, most cookies server 1 of 2 purposes:

  • Help web sites recognize visitors in order to provide them with the best possible service. Much like when I walk into my local barbershop and the barber recognizes me and knows exactly how I prefer him to cut my hair (the little I have left after reading crazy directives) – and which subjects I want to small talk about.
  • Visitor tracking in order to do statistics the site owners can use to improve the web site with. Again – it’s not all that different from when a grocery store owner thinks “wow – 10 customers this last week has asked me for low-fat milk. Perhaps I should start to carry that product here”.

I have no problem with both of the above scenarios – they fall into what I call good service and help enhance my online experience.
Another problem is that I generally dislike when legal stuff comes in the way for the best technical solution to a problem. Laws should describe the concept of what they are outlawing – not specific technical architectures such as cookies…But before I digress any further into political territory I’ll get right back on track.

Many ASP.NET developers rely on the Session State mechanism to store user relevant data within a visit, that can improve the user experience – for instance with personalization, prefilled forms, and so on. Unfortunately the Session state relies on a unique session key being stored in a local cookie in order to have a unique way to identify the same visitor throughout a visit. It actually comes with a built-in switch to make it stop using cookies – but unfortunately the solution looks rather ugly – it changes all the URLs on the site to contain a Guid and thereby track the visitor using the Guid. I, for one, am rather fond of clean and pretty friendly urls – so that’s no good. So – I started thinking…Many years ago I worked for a company that built a statistics tool. It was pretty unobtrusive and we didn’t use cookies. Instead we just tracked the source IP – and checked for repeated requests with a 10 minutes time-out. Sure, it wasn’t bullet-proof, but it actually worked surprisingly well. And in those cases where it didn’t work? Well – it was just 1 statistical entry out of many. It’s not like we used it to authorize access to the nuclear football, right?! Now, I thought that if we combine all the static information we get in the HTTP Request like IP, Accept Languages, Accept Types, User Agent and so on, smash it all together and take a fingerprint of it – we might end up with something that can almost be used as a session id. Consider: What are the odds that you’ll get 2 different visitors using the exact same configuration, coming from the exact IP on your site within the 20 minutes default time-out??
Of course it turns out I wasn’t the first to think this thought. In fact the clever people at the Electronic Frontier Foundation (EFF) has for some time been running a little example site that calculates those exact odds – just to prove that Privacy online isn’t solved by simply outlawing cookies.

So – I decided to put the thoughts into code. The code consist of 2 parts. First part is an extension method for the HttpRequest class, called “GetUniqueFingerprint()” which will return a MD5 Hash fingerprint.

using System;



using System.Collections.Generic;



using System.Linq;



using System.Web;



using System.Text;



using System.Security.Cryptography;



 



namespace AllanTech.NoCookie



{



    public static class NoCookies



    {



 



        static private string GetMd5Sum(string s)



        {



            Encoder enc = System.Text.Encoding.Unicode.GetEncoder();



            byte[] text = new byte[s.Length * 2];



            enc.GetBytes(s.ToCharArray(), 0, s.Length, text, 0, true);



            MD5 md5 = new MD5CryptoServiceProvider();



            byte[] result = md5.ComputeHash(text);



            StringBuilder sb = new StringBuilder();



            for (int i=0; i<result.Length; i++)



            {



                sb.Append(result[i].ToString("X2"));



            }



            return sb.ToString();



        }



 



        public static string GetUnqiueFingerprint(this HttpRequest Request)



        {



            string source=



                string.Join(",", Request.AcceptTypes)+";"+



                string.Join(",", Request.UserLanguages)+";"+



                Request.UserHostAddress+";"+



                Request.UserAgent;



            return GetMd5Sum(source);



        }



    }



}






Second part is a replacement for the ASP.NET SessionIDManager. This is the mechanism that uniquely identifies the visitor – either by a cookie or url – and by replacing it we can make it use our new UniqueFingerprint method instead. It’s really simple – just implement the ISessionIDManager and you’re good to go:





using System;



using System.Collections.Generic;



using System.Linq;



using System.Web;



using System.Web.SessionState;



 



namespace AllanTech.NoCookie



{



 



    public class CookielessIDManager : ISessionIDManager



    {



        public CookielessIDManager() { }



 



        #region ISessionIDManager Members



 



        public string CreateSessionID(HttpContext context)



        {



            return context.Request.GetUnqiueFingerprint();



        }



 



        public string GetSessionID(HttpContext context)



        {



            return context.Request.GetUnqiueFingerprint();



        }



 



        public void Initialize()



        {



            



        }



 



        public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)



        {



            supportSessionIDReissue=true;



            return context.Response.IsRequestBeingRedirected;



        }



 



        public void RemoveSessionID(HttpContext context)



        {



        }



 



        public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)



        {



            redirected=false;



            cookieAdded=false;



        }



 



        public bool Validate(string id)



        {



            return true;



        }



 



        #endregion



    }



}




Finally, all I have to do is to change the configuration (web.config) to use my CookielessIDManager instead of the default:



<sessionState mode="InProc" sessionIDManagerType="AllanTech.NoCookie.CookielessIDManager,AllanTech.NoCookie" … /> 



Enjoy a site with 1 less cookie!

15 comments:

Anders said...

Interresting, but how does this function with people surfing from work?

Often, workers have little or no option to tweak their environment, use the same browser (IE) with default setup, use the same hardware, and have the same external IP-address.

Allan Thræn said...

True, it's not bullet proof and I would never use this method to controlling access or security. However keep in mind that even in a controlled environment there might be some small configuration changes / difference in hardware, etc. And also keep in mind that in order to land in the same session they have to both be browsing your site with the same configuration from the same IP within a 20 minutes (default) time-out.
Maybe occasionally you'll get visitors "sharing" sessions - but then again - if that happens, what's the worst that could happen? If you do personalization there's even a fairly big possibility that the personalized content you offer will match both those otherwise similar visitors...

Muhammad Azeem said...

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

Anonymous said...

For high volume use scenario's. It wouldn't work out. It is inspiring in general.

fravelgue said...

Great post. I´m doing some similar but I´m trying to change cookiless behaviour. So I want to force to cookieless depends of domain and IPs (it´s useful for wap proxies).

The problem I get this error:

Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the \\ section in the application configuration.

I have tried to re-register modules, delete breakpoints, and other things that i found. But I can´t solve it. Do you found this problem implemting ISessionIDManager.

Thx in advance,

One more time thx for your post it´s very useful for me.

Pravesh Singh said...

Very nice article. I really enjoying it, and it also cleared lot of my doubts about Asp.Net session state. Thanks for sharing with us. Following link also helped me lot to understand the Asp.Net Session
State...

Session state in ASP.NET

Thanks everyone for your precious post!!

Anonymous said...

Technology is a body of knowledge used to create tools, develop skills, and extract or collect materials.

Joomla Developer

Unknown said...

Very helpful article, i easy for me as a beginner, if u looking for ASP.NET Hosting, i recommend asphostportal.com

Unknown said...

Good information! Your experiences are useful for development. Thank you.

Isa Guha said...

What are the solution for the arise by fact that HTTP being stateless? Is ASP.NET support any type of databases? Your blog is very informative and interesting, Please answer my 2 questions which I've asked your here, Its look like you are expert in it.

See Optimized360's 4 effective and affordable Medical Website Marketing designed primarily for physicians of all specialties. See stats from other practices.

Unknown said...

Good work…unique site and interesting too… keep it up…looking forward for more updates.Good luck to all of you and thanks so much for your hard-work.
asi legal bangalore, asi legal,asi legal kochin,Shahul hameed

Raj Maan said...

Nice and beautiful ideas. Thanks for sharing many information and collective images for aluminium scaffolding . putlocker

Unknown said...

tik tok shayari. st manufacturer and also a great company in allover delhi ncr Best Bra

Emma King said...

Digital commerce, also known as e-commerce , is indeed a business concept that allows businesses and individuals to buy and sell goods through the Internet. The growth of online developers in India has been fueled by advancements in the IT industry and increased consumer understanding of the Internet.
PPC company in India
PPC Company in USA
Social Media Marketing Agency in Delhi
Adwords- PPC Management Company Delhi
Website Development company in ranchi
Creative Web Development Company

Repute Agency said...

Thanks for sharing this website.
Best Website Development Company in Coimbatore

The Role of Social Media Marketing Services in Indian Businesses