Building A Custom ASP.NET 2.0 Session State Provider
Session stating although considered not directly related to security, does encapsulate some security related points. Although there aren’t many session related configuration changes that you can make in SharePoint, understanding the concept of session stating and why it exists will help understand the aggregate concept of how security works in SharePoint, as well as the ASP.NET 2.0 model.
The provider model as detailed in other articles is evident in many facets of SharePoint, and through the use of the Universal Provider model one can gain membership, role, and provider pluggable architectures.
Building a Pluggable Session State Provider
At the conclusion of this article, you will see how to extend this concept further, and construct a custom session state provider that you can use in an ASP.NET application that uses factory design patterns so that it is database agnostic, and can be used by any ASP.NET 2.0 application. Because of this type of framework, we won’t have to build multiple providers to use the session state provider with, rather, one can simply use this agnostic architecture in order to orphan different application session data, promoting a high level of isolation.
Introduction to Sessions
Session stating is an important concept in SharePoint, as well as ASP.NET 2.0 security as a whole. In the new version of SharePoint, session stating is something that is always present and usable, in every page that you call within an ASP.NET 2.0 application. The backbone of session stating is the session object, which is the place where one can store various session information related to a specific application. In regards to session stating, there are several robust configuration options that are available, however some noteworthy limitations that exist as well. The Session objects core property is the SessionID (which is referred to as the session identifier, which is Session.SessionID), which becomes increasingly important when we begin looking at manipulating sessions, or sessionID’s.
The newest concept that exists in ASP.NET 2.0 is the option to use cookie-less sessions in regards to OOB session state providers and custom session state providers that are built on the ASP.NET 2.0 pluggable provider framework. There are obvious security concerns that exist with this type of functionality, because session states are relatively easy to hijack and are prone to be session reuse (as will be detailed more below in the comparison with login tickets, and the session reuse a little further down), storing things that would normally be stored in cookies such as usernames is typically a bad move.
Session stating has four main modes that are offered, In Process, SQL Server, State Server, and Custom (which will leverage the custom provider that we will see how to build shortly). When storing session data in a database, there are some implications that have to be taken into consideration before implementing it, and this becomes a concern when building a custom provider that will use an arbitrary data store. A major concepts that have to be taken into consideration are trust levels (to deal with CAS issues).
Sessions States Are Not Authentication Tickets
A common misconception about session states is that they are the same as a user login process and related login services. Session data is simply a numeric check against the 120-bit identifier that ASP.NET generates, in essence strongly checking the session identifier. In aggregate, a user enters a session enabled ASP.NET 2.0 application with will generate a session identifier, which is 120-bits, and is randomly generated, then the identifier can be sent back to ASP.NET which does some rudimentary syntax checks, and then the related data that was a available in that session is then available to the user. It would be pretty easy for a malicious user trying to hijack a session to generate a session identifier, send to ASP.NET, and then snatch a session. However, with authentication tickets (going back to the original point of the difference between session identifiers and authentication tickets), this would be near impossible, since the authentication tickets mathematical backbone is much more complex since it would require the guessing of several encryption keys.
Trust Levels and a Custom Session Provider
The first concept to take into consideration are the trust levels that need to be taken into consideration when implementing a custom session provider. For other types of session state modes, there are various required trust levels that are necessary that are not the same as those required by a custom provider. Meaning, if you are implementing SQL server session state mode then the trust level that is required is medium. For the other remaining sessions state modes, in process and state server, for the first there is the requirement of a minimal trust level, and for the latter, a medium trust level is required. For our custom provider, we require a trust level of minimal, however this can be modified if higher CAS security requirements are necessary within an arbitrary environment.
Why does the custom provider require a minimal trust level? The code stack for the provider as you will see is written in managed code, and lives instead the global assembly cache. Assuming that all the code that is going to be called from the provider also lives within the global assembly cache, there is no reason why there should be other trust level applied. Because we are going to deploy the custom provider to the GAC, it is important to pay attention to the code, and how the code will execute in terms of hooking into other .NET framework assets, since it will bypass several CAS concerns and will typically run without permission issues.
What is Session Partitioning?
Using a pluggable provider model allows a developer to approach sessions stating with a flexible backend data store whereby session data is easy to store. A common requirement is the sharing of session information across multiple session applications, or the lack thereof in order to prevent session collisions or unwanted session information sharing. When using a custom session state provider, the process is considered to be in-process , which is important to recognize because the relevant information will be stored in the cache object. Because of this, the level of isolation between the session information is high, and the session information will be segregated into the relevant application domains.
However, because we are using a custom session state provider, we get some benefits that will allow us to break this level of isolation if we choose in beneficial ways. Using a custom session state provider we can breakdown this concept of isolation into a central session state repository where we can store all application session state data whereby session information can be stored.
Reusing Session Information
Session ID information can optionally be reused, however in cookieless mode this options is disabled, instead new session information is applied (a new session object being instantiated) when session data expires or the SID is housed in the client URL, as detailed more exhaustively in the below section. In cookied mode, this is a very powerful concept however, since cookied mode allows the use of session information across multiple applications assuming that they are all under the same DNS host. Therefore, even if the session information is flushed on one application it can still be used on an arbitrary number of applications within an enterprise. This is not the case where the session is abandoned (literally, since one has to call Session.Abandon), meaning that if a session is abandoned in one application, new session information has to applied, however the session information can be valid across n number of other applications.
One of the largest parts to consider about session stating is what happens when a session expires, and how sessions are managed through their lifecycle, particularly towards the latter end of the cycle. Expiration of sessions is handled differently in cookie â€“based and cookie-less session modes. When cookie-less sessions are used, new sessionID’s are generated when the sessions data is expired, or when there is a pre-existing SID, appended to the URL that the client is attempting to access. With cookie sessions enabled, this activity is much different operationally.
A concern revolving sessions is that a session can theoretically never expire, as long as there is activity within a specific SessionID, the ID will always be there. ASP.NET 2.0 deals with this however with an attribute called regenerateExpiredSessionId. regenerateExpiredSessionId relates to the concept introduced above where the session information is stored in the client URL. Because it would be bad security practice to allow sessionID’s to exist in the URL across browser sessions, this allows the SessionID to be regenerated when cookieless sessions state is enabled and the session information is housed in the client URL.
Utilizing a Pluggable Provider Model
Utilizing the pluggable provider model available to ASP.NET 2.0 is indeed a powerful mechanism that allows several layers of flexibility in the operational functionality of session stating. In this section, we will see how to use that model to build a session state provider that is based on pattern designs so that it ignores concrete provider bindings and is instead blind to the database backend that is being used. As stated in other portions of this article, there are added benefits to this, namely because with in-process session stating the session information will be segregated into application domains, it is quote isolated. If we wanted to establish a central repository that shared session information, an agnostic provider would help to achieve this.