ISessionStateItemCollection interface

Summary

In previous programming projects, I have used the ISessionStateItemCollection object to override the session state collection object built into HttpContext.Current.  In this blog post I’m going to demo a bug in Microsoft’s sample code used to show how to create a custom SessionStateItemCollection.

Where to Find the Sample Code

Microsoft provides a lot of sample code for objects that you can customize.  The session state collection is one example.  The ISessionStateItemCollection interface is detailed on this webpage:  IsessionStateItemCollection Interface.  Each property and method is described in detail to make it easy to design a custom object.  If you scroll down the page, you’ll see a sample custom interface that uses the SortedList object to contain the item collection.  If you copy the code and paste it into Visual Studio, it will run as advertised.  Here’s a sample of some code you can execute in a console application:

var sessionTest = new MySessionStateItemCollection();

sessionTest[“test“] = “test data“;

Console.WriteLine(sessionTest[“test“]);

Console.ReadKey();

 Unfortunately, there is a problem with the key collection cast.  If you attempt to run this code, you’ll see the run-time casting error:

var sessionTest = new MySessionStateItemCollection();

sessionTest[“test“] = “test data“;

Console.WriteLine(sessionTest.Keys.Count);

Console.ReadKey();


 The error message looks like this:


If you’re like me, you’ll copy the error message and paste it into Google and attempt to find a solution.  That solution normally shows up on Stack Overflow, but sometimes if it’s not on that website you’ll stumble across it someplace else.  The solution to this error, is nowhere to be found.  I suspect that very few programmers write a custom session state item collection and those who do, have found a work-around.  So I’m posting a work-around to this issue that is not fantastic, but it works.

First, remove the line of code containing the SortedList.  Then add a base class to the object like this:

public class MySessionStateItemCollection : NameObjectCollectionBase, ISessionStateItemCollection

Next, you’ll need to alter all the method calls that used the SortedList (pItems).  You can use base.BaseGet(index) and base.BaseSet(index), etc.  You can override the Keys property and it will cast correctly, or you can just remove it since the base class implements that property already.  You’ll have to perform some fancy footwork for the CopyTo() method, since it is not implemented in the base class.

A second solution to this problem is to implement your own NameObjectCollectionBase type.  You could technically, implement a custom collection that mirrors the built-in methods of the NameObjectCollectionBase class.  This object also has sample code from Microsoft and this code works as advertised (see NameObjectCollectionBase Class).

 

Creating Your Own Custom Session ID (Part 2)

Summary

In my last post, I talked about how to override the id generator of the HttpContext.Current.Session.  In this post I’m going to show how to override the methods that affect the cookie itself.

The ISessionIDManager Interface

In order to get at the methods required to manipulate the cookie, you’ll need to implement the ISessionIDManager Interface.  If you’re using Visual Studio 2015, this is an opportunity to use a new feature.  If you create a new solution and add a library project, then add a using for “System.Web.SessionState” and add the “System.Web” reference.  Now you can create a class that looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;

namespace MyCustomSession
{
    public class CustomSessionIDManager : ISessionIDManager
    {

    }
}

The ISessionIDManager statement will have a red wavy line under it.  If you hover over that keyword, you’ll get the following drop-down:

 Now you can click on the “Show Potential Fixes” link, then click on “Implement Interface”.  Then all the necessary methods and properties will be auto-populated:

So you’ll end up with something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;

namespace MyCustomSession
{
    public class CustomSessionIDManager: ISessionIDManager
    {
        public string CreateSessionID(HttpContext context)
        {
            throw new NotImplementedException();
        }

        public string GetSessionID(HttpContext context)
        {
            throw new NotImplementedException();
        }

        public void Initialize()
        {
            throw new NotImplementedException();
        }

        public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)
        {
            throw new NotImplementedException();
        }

        public void RemoveSessionID(HttpContext context)
        {
            throw new NotImplementedException();
        }

        public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
        {
            throw new NotImplementedException();
        }

        public bool Validate(string id)
        {
            throw new NotImplementedException();
        }
    }
}

In case you’re wondering, this is the free Visual Studio Community 2015 version.  I’m evaluating the features that are available and it appears that Microsoft has finally produced a free version of Visual Studio that can be used to produce real software.  I’m still expecting to run into a limitation at some point, but so far, I’ve been using 2015 Community as though it has the same features as my old Visual Studio 2013 Professional.

Implementing the Interface

In my last blog post, I already implemented the CreateSessionID() and Validate() methods, so I’m going to copy and paste that code over from that project.  Again, Microsoft has a sample that you can use for your template.  It can be found at this website: ISessionIDManager Interface.

The first problem that I discovered when using the code provided from Microsoft is that the GetSessionID() method give an error at the “context.Request.Cookies[pConfig.CookieName].Value;” line.  The cookie has not been created and the SaveSessionID() method does not get called before this method is called.

The second thing I noticed is that the implementation of the IHttpModule methods seems pointless.  They also never get called.  I’m betting that there are methods in IHttpModule that are handy for certain features of the Session id, but they are not needed for this demonstration.

Don’t forget to setup your web.config file to invoke your custom object:

<configuration>
    <system.web>
        <sessionState cookieName=”MySessionID” 

            sessionIDManagerType=”MyCustomSession.CustomSessionIDManager,  
            MyCustomSession” />
    </system.web>
</configuration>

To fix the issue with the cookie not being created on initial load, I did this:

public string GetSessionID(HttpContext context)
{
    string id = null;

    if (pConfig.Cookieless == HttpCookieMode.UseUri)
    {
        // Retrieve the SessionID from the URI.
    }
    else
    {
        if (context.Request.Cookies[pConfig.CookieName] == null)
        {
            bool redirected;
            bool cookieAdded;

            SaveSessionID(context, id, out redirected, out cookieAdded);
        }
        else
        {
            id = context.Request.Cookies[pConfig.CookieName].Value;
        }
    }

    // Verify that the retrieved SessionID is valid. If not, return null.

    if (!Validate(id))
    {
        id = null;
    }

    return id;
}

If anybody out there has the correct solution to this problem, please drop me a comment.  If I find a solution, I’ll post an update to this blog entry.  I’m assuming that the calling object is supposed to recognize when a cookie doesn’t exist and call the SaveSessionID() method automatically.  However, that doesn’t happen here for some reason.


Where to Get the Code


As usual, you can go to my GitHub account and download the working project by clicking here.



 


 

 

Creating Your Own Custom Session ID

Summary

In this blog post I’m going to talk about the ID manager used by the .Net HttpContext.Current.Session and how to customize the ID that is generated to create a more secure ID.

Session ID

The session ID that is created when you use the Session object is contained in a cookie named ASP.NET_SessionId by default.  You can override the cookie name in the web.config file by using the following syntax:

<configuration>
    <system.web>
        <sessionState cookieName=”MySessionID” />
    </system.web>
</configuration>
 

This will cause the cookie to be named “MySessionID”.  You can also set the session to become cookieless.  I’m not go into cookieless sessions in this blog post.  What I am going to talk about is how to override the mechanism that generates the actual session id stored inside the cookie.  In a future blog post I’ll take this further and discuss how the cookie generation code can be modified to give you more control over this process.

The default .Net algorithm that is used to generate the id uses lower case characters ‘a’ thorugh ‘z’ and the numbers ‘0’ through ‘5’.  The reason for this sequence is that they are safe to use in a URL if you switch to cookieless.  The choice of only 6 numbers is due to the fact that the total characters to choose from becomes 32, which is an even binary number.  That allows the random number generator used to choose the letter for each digit to be un-biased.  For an excellent article about random number biasing when using the mod function I’ll refer you to this blog post: How much bias is introduced by the remainder technique?

The SessionIDManager Object

The SessionIDManager object is what performs the id generation and I’m going to show how to override the CreateSessionID() and Validate() methods in order to generate your own session id.  Microsoft has sample code here: SessionIDManager.CreateSessionID Method (HttpContext) using a GUID for the id.  DON’T DO IT THIS WAY!  This is a very simple and quick way to generate a custom id, but it’s also relatively easy to hack.  The problem with the GUID is that it is unique, but it is not random.  It’s pseudo-random and predictable.  If you refer to RFC4122, section 6:

Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example. A predictable random number source will exacerbate the situation.

Make sure you use a cryptographically random number generator.  For this we can use the RNGCryptoServiceProvider object.  In addition to this, I’m going to make the key length 64 characters (you can go up to 80).  Here’s the C# code in total:

using System.Web;
using System.Web.SessionState;
using System.Security.Cryptography;
using System.Linq;

namespace MyCustomSession
{
    public class CustomSessionIDManager : SessionIDManager
    {
        public const int KEY_LENGTH = 64;
        private char[] Encoding = {
            ‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘, ‘g‘, ‘h‘, ‘i‘, ‘j‘, ‘k‘, ‘l‘, ‘m‘,
            ‘n‘, ‘o‘, ‘p‘, ‘q‘, ‘r‘, ‘s‘, ‘t‘, ‘u‘, ‘v‘, ‘w‘, ‘x‘, ‘y‘, ‘z‘,
            ‘0‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘ };

        public override string CreateSessionID(HttpContext context)
        {
            char[] identifier = new char[KEY_LENGTH];
            byte[] randomData = new byte[KEY_LENGTH];

            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(randomData);
            }

            for (int i = 0; i < identifier.Length; i++)
            {
                int pos = randomData[i] % Encoding.Length;
                identifier[i] = Encoding[pos];
            }

            return new string(identifier);
        }

        public override bool Validate(string id)
        {
            try
            {
                if (id.Length != KEY_LENGTH)
                {
                    return false;
                }

                for (int i=0; i < id.Length; i++)
                {
                    if (!Encoding.Contains(id[i]))
                    {
                        return false;
                    }
                }

                return true;
            }
            catch
            {
            }

            return false;
        }
    }
}

And you’ll need to modify your web.config to match:

<configuration>
    <system.web>
        <sessionState cookieName=”MySessionID” 

            sessionIDManagerType=”MyCustomSession.CustomSessionIDManager,  
            MyCustomSession” />
    </system.web>
</configuration>


You’ll notice that MyCustomSession is used twice in the sessionIDManagerType definition.  The first one is the namespace and the name after the comma is the name of the dll.

I used the same character encoding that Microsoft uses, but you can increase the charactors to increase your security.  Just make sure you use an even binary number like 64 characters.  Also be aware of characters that might be difficult to work with (like the period, commas, back-slash, less-than, greater-than, etc.).  If you use upper case letters, lower case letters and all numbers you’ll end up two characters short of 64 characters.  So you’re forced to use two non-number/non-letter characters.

The next thing to note about the above class is that there is a validate() method.  This opens up some possibilities for a custom sequence that you can use to prevent spoofing.  In such a case I would try and keep such information classified so an outsider has difficulty in spoofing your id.  In the sample above, I’m only checking to make sure that the length is exactly correct and that each character in the id is in the list of valid characters.


Where to Get the Code

I have posted this example on my GitHub account and you can download it by clicking here.  This was written in Visual Studio 2015, but you can use it in earlier versions of Visual Studio.


 

Generating a Custom Session Token

Summary

In this post I’m going to demonstrate how to generate a safe token for a custom session module.

The Session Token

When a user logs into a website, there needs to be a way to keep track of who the person is after the authentication occurs.  One method is to give the user a token after they log in and carry it around in a hidden field.  Another method used by Microsoft is to embed the token in the URL itself.  The token can also be placed in the authenticate field of the header.  Last, and most common the token can be stored in a local cookie that is non-persistent (in other words it goes away when the browser closes, unless you’re using Chrome).  For this blog post, it doesn’t really matter where the token is stored and used, I’m going to discuss the security of the token itself.

The first requirement is that you need to issue a unique token every time someone logs in and maintain a relationship between the user and the token (most likely in your database).  There was a security breach a few years ago involving a secure website that use the account number as their token (I can’t remember the company off the top of my head).  They also used it in the URL, which means that anybody looking over your shoulder can get your account number.  In addition to this problem, I’m betting that their account numbers were sequentially issued.  So a user could potentially log in, then modify the number in the URL and navigate around someone else’s account.  Probably one of the worse implementations I’ve ever encountered.

So we need a unique key and the first thing that comes to mind is the GUID.  Sounds good.  In C# we can get a new GUID quickly.  We can strip out the dashes if we like and just treat it as a string.  One limitation to the GUID is that they are not unique if you take a subset of the GUID.  In other words, you’ll need the whole thing.  There is, however, another problem: The GUID sequence is predictable.  The GUID is also hex, not really a string of characters, so the permutations is much smaller than it appears.

While I was reading about GUIDs, I came across this article at stack overflow:

Generating random string using RNGCryptoServiceProvider 

This particular algorithm uses the RNGCryptoServiceProvider() to get a encrypted random number.  The algorithm cited is supposed to generate 40 character random strings that are very distant from each other.  So the test I want to perform uses the Levenshtein distance algorithm between each random generated string.

When I run 50,000 random strings comparing a string with it’s previous string I get a minimum difference in letters of 34, and an average of 39.  That means that at least 34 of the 40 letters were different as a minimum and on average at least 39 letters will be different.

Where to Get the Code

You can download the sample code from my GitHub account here and modify the parameters.
 

 

Web Sessions

Summary

I’m going to create a series about how Microsoft handles sessions for VB.Net and C# web applications.  The purpose of these posts will be to provide a clearing-house of all the information needed to get a common session system going between multiple languages.

The Problem

Web sites typically use session data to keep track of who is logged in and what state they are in.  I’m not going to go into details on why sessions are used or how to use them to build a website.  Instead, I’m going to assume you are already familiar with this technique and you’re saddled with a large amount of legacy code that cannot be converted in one shot.  Let’s say you have a website in PHP and you’re attempting to migrate into a C# environment.  How do you go from one web page in PHP running on a Unix server into a C# program running on an IIS server?

There are many solutions, such as cookies, tokens passed in the URL, a GUID stored in a hidden field, etc.  The smoothest solution would be to somehow share the session data between different languages so that one page at a time can be converted and the URL from the old page can be redirected to the new page with a smooth and secure transition.  The first thing to recognize is that we’re going to have to store the session data in a database that is shared by all web sites that will be connected into one web application.  Microsoft provides this capability through their own session management.  

Using MS SQL Server to Store Session Data

For Dot Net applications, you can setup a SQL server to store the session data.  The following link is probably your best article for getting SQL setup with the ASPState database and redirecting your application to point to the new database:

Configuring ASP session state on SQL server 

Once you have set this up, you’ll need to make sure your user rights are setup in the ASPState and the tempdb database.  The session data is actually stored in the tempdb database in two tables: ASPStateTempApplications and ASPStateTempSessions.  The ASPStateTempApplications table contains the name of the application and the unique app id used by the session cookie (I’m going to assume you’re using the cookie mode in iis, since it is the default).  The ASPStateTempSessions table contains one record per session created.  All of the session data is encoded and stored in a binary field in this table called SessionItemShort (or if it’s larger than 7k, then it’ll be in SessionItemLong which is an image data type).


The Session Cookie

When your application creates a session, a cookie is created with the application id and a unique session id.  The default cookie name is “ASP.NET_SessionId”.  If you look at the session id the tempdb.ASPStateTempSessions table, you’ll discover that it is a large alphanumeric string.  That string represents two parts: The session GUID and the application ID.  The application ID is in hex in the ASPStateTempSessions table and it is in decimal in the ASPStateTempApplication.appid field.  If you are going to read the session data from the tempdb database ASPStateTempSessions table, then you’ll need to add the application ID to the end the cookie value.  Take your application name and read the application id from the ASPStateTempApplications table.  Convert this to hex, then append to the cookie value.  This will be the primary key of the ASPStateTempSessions table for your session data.

If your googling skills are savvy enough, you will have discovered most of this information from this article: Session State Providers.  

The next thing to note about this session setup is that the cookie is a non-persistent cookie.  There is no expire date and this type of cookie will remain until you close your browser.

If you dig into your SQL server and you look at your SQL Server Agent jobs, you’ll see a new one called ASPState_Job_DeleteExpiredSessions.  This job will execute the stored procedure: DeleteExpiredSessions once per minute.  The sole purpose of this stored procedure is to delete all cookies where the expires field is beyond the current date/time.  This will cause the session to expire.  If you look at this date/time in the
ASPStateTempSessions table, then refresh your browser, you’ll notice that the time updates.  The time will always be 20 minutes into the future (if your session is set to expire in 20 minutes, which is the default).  If your web page goes idle for more than 20 minutes, then you’re toast.


Sharing Session Data Between VB.Net and C#

The easy method of sharing between two languages is to set the application name to the same name in the global.asax file for both programs:

Session State shares session across subdomain, VB.NET website C# MVC 4 Application


Session Data

The session data that is stored in the tempdb.ASPStateTempSessions table is an encoded version of all the session variables and data used by your program.  There is this code in C#, which can decode this data into a list of variables:

christian-blades-cb/ASPSessionDecoder 

This code does not handle objects, but it does demonstrate the complexity of how this is encoded.  Creating an encoder and decoder for this data for a multitude of languages would be very handy.  Especially if you wanted to use many languages in one large monolithic application.  I believe the reason that Microsoft encoded this data into one large field instead of using a sub-table of fields and data, is that they can store the session data for each session in one record.  This prevents a lot of table locking issues with deleting records and it also reduces the amount of time it takes to read and write to the database (assuming they had a database in mind when they designed this system.  If you look closely at the DeleteExpiredSessions stored procedure inside the ASPState database, you’ll see that a query of all the expired sessions is put into a temp table.  Then the temp table is looped through and each session record is re-checked as it is deleted, just in case it was updated or deleted while this operation was in progress.


Wrap up

For this blog post, that’s all I’m going to go into.  Armed with this information anybody can make a decision on how they want to pursue sessions with legacy code and new code.  For instance, you could design your own session system to mimic what Microsoft does and use child records to store your variables.  I am unsure how this will perform or what issues you’ll run into with this method.  You could write encoders and decoders for the session data and use the data that Microsoft stores (avoiding the need for converters and decoders from VB.Net and C# (i.e. you could write a codec for PHP, Classic ASP, Java).  By storing your session in the database, you can use different IIS applications for each language (or divide your systems into multiple applications).  You can also prevent your session from clearing when an IIS server is re-cycled, or if you have a server farm, you don’t need to worry about which server the web request returns to.