Monday, December 28, 2009

Secure your cookies

Recently our IT Risk team suggested us to hide our cookies as part of making our site more secure. One of their main concerns were that all cookie names suggest exactly what data is stored. So we came up with the following solution.

First abstract the cookies to a new class called WebCookie.
Based on our requirement we only need to make sure that the cookies expire after a specified number of seconds.

[Serializable]
public class WebCookie
{
   private string _Name = "";
   public string Name
   {
    get { return _Name; }
    set { _Name = value; }
   }
   private string _Value = "";
   public string Value
   {
    get { return _Value; }
    set { _Value = value; }
   }
   private int _ExpiresInSeconds = 1200;
   public int ExpiresInSeconds
   {
    get { return _ExpiresInSeconds; }
    set { _ExpiresInSeconds = value; }
   }
   public WebCookie() { }
   public WebCookie(string name, string value)
   {
    _Name = name;
    _Value = value;
   }
   public WebCookie(string name, string value, int expiresInSeconds)
   {
    _Name = name;
    _Value = value;
    _ExpiresInSeconds = expiresInSeconds;
   }
}

Use the base web page to store these cookies as a dictionary. Also expose some methods to add/read cookies.

private Dictionary<string, WebCookie> _WebCookies = new Dictionary<string, WebCookie>();

public void SetCookie(string name, string value)
{
   string keyName = name.ToUpper();
   if (_WebCookies.ContainsKey(keyName))
    _WebCookies[keyName].Value = value;
   else
    _WebCookies.Add(keyName, new WebCookie(name, value));
}

public WebCookie GetCookie(string name)
{
   string keyName = name.ToUpper();
   if (_WebCookies.ContainsKey(keyName))
    return _WebCookies[keyName];
   return null;
}

On pre render, serialize the dictionary, then encrypt and send it as cookie. Also make sure to add the Cookie generated time to the dictionary before serializing. We can use this time stamp later to findout which cookie items have timed out.

private string _CookieName = "__CookieStore__";
private string _LastPostTimeCookieKeyName = "LastPostTime";
protected override void OnPreRender(EventArgs e)
{
   _WebCookies.Add(_LastPostTimeCookieKeyName, new WebCookie(_LastPostTimeCookieKeyName, DateTime.Now.Ticks.ToString()));
   LosFormatter los = new LosFormatter();
   StringWriter sw = new StringWriter();
   los.Serialize(sw, _WebCookies);
   string cookieValueToStore = sw.GetStringBuilder().ToString();
   // Encrypt cookieValueToStore to make it more secure.
   HttpCookie cookie = new HttpCookie(_CookieName, cookieValueToStore);
   Response.Cookies.Add(cookie);
   base.OnPreRender(e);
}

On pre init, read the cookie and populate the dictionary. Also check the last post time to findout which items have really timed out.

protected override void OnPreInit(EventArgs e)
{
   if (Request.Cookies[_CookieName] != null && !string.IsNullOrEmpty(Request.Cookies[_CookieName].Value))
   {
    string cookieValue = Request.Cookies[_CookieName].Value;
    // Decrypt it, if you've encrypted it.
    LosFormatter los = new LosFormatter();
    _WebCookies = los.Deserialize(cookieValue) as Dictionary<string, WebCookie>;
    if (_WebCookies.ContainsKey(_LastPostTimeCookieKeyName))
    {
       _LastPostTime = new DateTime(long.Parse(_WebCookies[_LastPostTimeCookieKeyName].Value));
       _WebCookies.Remove(_LastPostTimeCookieKeyName);
    }
    // Remove all items which are expired.
   }
   base.OnPreInit(e);
}

Now you have secured your cookies.
Enjoy!!!

No comments:

Post a Comment