Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a new ASP.NET session in the current HTTPContext

As a result of a penetration test against some of our products in the pipeline, what looked to be at the time an 'easy' problem to fix is turning out to be a toughy.

Not that it should of course, I mean why would just generating a brand new session for the current HTTPContext be so difficult? Bizarre! Anyway- I've written a cheeky little utility class to "just do it":

(apologies for code formatting/highlighting/Visual Basic I must be doing something wrong)

 Imports System.Web Imports System.Web.SessionState  Public Class SwitchSession      Public Shared Sub SetNewSession(ByVal context As HttpContext)         ' This value will hold the ID managers action to creating a response cookie         Dim cookieAdded As Boolean         ' We use the current session state as a template         Dim state As HttpSessionState = context.Session         ' We use the default ID manager to generate a new session id         Dim idManager As New SessionIDManager()         ' We also start with a new, fresh blank state item collection         Dim items As New SessionStateItemCollection()         ' Static objects are extracted from the current session context         Dim staticObjects As HttpStaticObjectsCollection = _             SessionStateUtility.GetSessionStaticObjects(context)         ' We construct the replacement session for the current, some parameters are new, others are taken from previous session         Dim replacement As New HttpSessionStateContainer( _                  idManager.CreateSessionID(context), _                  items, _                  staticObjects, _                  state.Timeout, _                  True, _                  state.CookieMode, _                  state.Mode, _                  state.IsReadOnly)         ' Finally we strip the current session state from the current context         SessionStateUtility.RemoveHttpSessionStateFromContext(context)         ' Then we replace the assign the active session state using the replacement we just constructed         SessionStateUtility.AddHttpSessionStateToContext(context, replacement)         ' Make sure we clean out the responses of any other inteferring cookies         idManager.RemoveSessionID(context)         ' Save our new cookie session identifier to the response         idManager.SaveSessionID(context, replacement.SessionID, False, cookieAdded)     End Sub  End Class 

It works fine for the remainder of the request, and correctly identifies itself as the new session (e.g. HTTPContext.Current.Session.SessionID returns the newly generated session identifier).

Surprise surprise then, that when the next request hits the server, the HTTPContext.Session (an HTTPSessionState object) identifies itself with the correct SessionID, but has IsNewSession set to True, and is empty, losing all the session values set in the previous request.

So there must be something special about the previous HTTPSessionState object being removed from the initial request, an event handler here, a callback there, something which handles persisting the session data across requests, or just something I'm missing?

Anybody got any magic to share?

like image 422
Rabid Avatar asked Sep 02 '09 15:09

Rabid


People also ask

What is the difference between session and HttpContext current session?

There is no difference. The getter for Page. Session returns the context session.

What is the use of HttpContext current?

HttpContext is an object that wraps all http related information into one place. HttpContext. Current is a context that has been created during the active request. Here is the list of some data that you can obtain from it.

How is ASP NET_SessionId generated?

NET_SessionId has been created by the server and set in the Response Header. Now an ASP. NET_SessionId has been created by the web server so in the next requests, the Request Header has that ASP. NET_SessionId and it is the same as the Response Header.

How do I clear HttpContext current session value?

Session. Clear() just removes all values (content) from the Object. The session with the same key is still alive.


1 Answers

I would like to share my magic. Actually, no, its not yet magical.. We ought to test and evolve the code more. I only tested these code in with-cookie, InProc session mode. Put these method inside your page, and call it where you need the ID to be regenerated (please set your web app to Full Trust):

void regenerateId() {     System.Web.SessionState.SessionIDManager manager = new System.Web.SessionState.SessionIDManager();     string oldId = manager.GetSessionID(Context);     string newId = manager.CreateSessionID(Context);     bool isAdd = false, isRedir = false;     manager.SaveSessionID(Context, newId, out isRedir, out isAdd);     HttpApplication ctx = (HttpApplication)HttpContext.Current.ApplicationInstance;     HttpModuleCollection mods = ctx.Modules;     System.Web.SessionState.SessionStateModule ssm = (SessionStateModule)mods.Get("Session");     System.Reflection.FieldInfo[] fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);     SessionStateStoreProviderBase store = null;     System.Reflection.FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;     foreach (System.Reflection.FieldInfo field in fields)     {         if (field.Name.Equals("_store")) store = (SessionStateStoreProviderBase)field.GetValue(ssm);         if (field.Name.Equals("_rqId")) rqIdField = field;         if (field.Name.Equals("_rqLockId")) rqLockIdField = field;         if (field.Name.Equals("_rqSessionStateNotFound")) rqStateNotFoundField = field;     }     object lockId = rqLockIdField.GetValue(ssm);     if ((lockId != null) && (oldId !=null)) store.ReleaseItemExclusive(Context, oldId, lockId);     rqStateNotFoundField.SetValue(ssm, true);     rqIdField.SetValue(ssm, newId); } 

I have been digging around .NET Source code (that were available in http://referencesource.microsoft.com/netframework.aspx), and discovered that there is no way I could regenerate SessionID without hacking the internals of session management mechanism. So I do just that - hack SessionStateModule internal fields, so it will save the current Session into a new ID. Maybe the current HttpSessionState object still has the previous Id, but AFAIK the SessionStateModule ignored it. It just use the internal _rqId field when it has to save the state somewhere. I have tried other means, like copying SessionStateModule into a new class with a regenerate ID functionality, (I was planning to replace SessionStateModule with this class), but failed because it currently has references to other internal classes (like InProcSessionStateStore). The downside of hacking using reflection is we need to set our application to 'Full Trust'.

Oh, and if you really need the VB version, try these :

Sub RegenerateID()     Dim manager     Dim oldId As String     Dim newId As String     Dim isRedir As Boolean     Dim isAdd As Boolean     Dim ctx As HttpApplication     Dim mods As HttpModuleCollection     Dim ssm As System.Web.SessionState.SessionStateModule     Dim fields() As System.Reflection.FieldInfo     Dim rqIdField As System.Reflection.FieldInfo     Dim rqLockIdField As System.Reflection.FieldInfo     Dim rqStateNotFoundField As System.Reflection.FieldInfo     Dim store As SessionStateStoreProviderBase     Dim field As System.Reflection.FieldInfo     Dim lockId     manager = New System.Web.SessionState.SessionIDManager     oldId = manager.GetSessionID(Context)     newId = manager.CreateSessionID(Context)     manager.SaveSessionID(Context, newId, isRedir, isAdd)     ctx = HttpContext.Current.ApplicationInstance     mods = ctx.Modules     ssm = CType(mods.Get("Session"), System.Web.SessionState.SessionStateModule)     fields = ssm.GetType.GetFields(System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)     store = Nothing : rqLockIdField = Nothing : rqIdField = Nothing : rqStateNotFoundField = Nothing     For Each field In fields         If (field.Name.Equals("_store")) Then store = CType(field.GetValue(ssm), SessionStateStoreProviderBase)         If (field.Name.Equals("_rqId")) Then rqIdField = field         If (field.Name.Equals("_rqLockId")) Then rqLockIdField = field         If (field.Name.Equals("_rqSessionStateNotFound")) Then rqStateNotFoundField = field     Next     lockId = rqLockIdField.GetValue(ssm)     If ((Not IsNothing(lockId)) And (Not IsNothing(oldId))) Then store.ReleaseItemExclusive(Context, oldId, lockId)     rqStateNotFoundField.SetValue(ssm, True)     rqIdField.SetValue(ssm, newId)  End Sub 
like image 191
YudhiWidyatama Avatar answered Sep 27 '22 22:09

YudhiWidyatama