tag route password page net mvc for data asp all asp.net session-state sessionid httpsession

route - Generando una nueva sesión de ASP.NET en el HTTPContext actual



partial views asp net mvc (5)

Como resultado de una prueba de penetración en contra de algunos de nuestros productos en la tubería, lo que parecía ser en ese momento un problema ''fácil'' de arreglar está resultando difícil.

No es que deba hacerlo, por supuesto, me refiero a por qué sería tan difícil generar una nueva sesión para el HTTPContext actual . ¡Extraño! De todos modos, escribí una pequeña clase útil de utilidad para "simplemente hazlo":

(disculpas por el formato del código / resaltar / Visual Basic debo estar haciendo algo mal)

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

Funciona bien para el resto de la solicitud, y se identifica correctamente como la nueva sesión (por ejemplo, HTTPContext.Current.Session.SessionID devuelve el identificador de sesión recién generado).

Sorpresa sorpresa entonces, que cuando la próxima solicitud llega al servidor, HTTPContext.Session (un objeto HTTPSessionState ) se identifica con el SessionID correcto, pero tiene IsNewSession establecido en True y está vacío, perdiendo todos los valores de sesión establecidos en la solicitud anterior .

Entonces, debe haber algo especial sobre el objeto HTTPSessionState anterior que se elimina de la solicitud inicial, un controlador de eventos aquí, una devolución de llamada allí, algo que maneja la persistencia de los datos de la sesión entre las solicitudes, o simplemente algo que me falta.

¿Alguien tiene magia para compartir?


¿Ha considerado utilizar el método HttpSessionState.Abandon ? Eso debería limpiar todo. Luego inicie una nueva sesión y rellene con todos los elementos almacenados desde su código anterior.

Session.Abandon(); debería ser suficiente. De lo contrario, podría tratar de hacer un esfuerzo adicional con unas pocas llamadas más si todavía es obstinado:

Session.Contents.Abandon(); Session.Contents.RemoveAll();


¿No puedes simplemente establecer:

<sessionState regenerateExpiredSessionId="False" />

en web.config, y luego usar la solución sugerida por Ahmad?


Como mencionó Can Gencer, ReleaseItemExclusive no elimina la sesión anterior de la tienda y eso lleva a que esa sesión expire y llame a Session_End en Global.asax. Esto nos causó un gran problema en la producción, porque estamos borrando la identidad del subproceso en Session_End, y debido a esto, los usuarios estaban perdiendo espontáneamente la autenticación en el hilo.

A continuación se muestra el código corregido que funciona.

Dim oHTTPContext As HttpContext = HttpContext.Current Dim oSessionIdManager As New SessionIDManager Dim sOldId As String = oSessionIdManager.GetSessionID(oHTTPContext) Dim sNewId As String = oSessionIdManager.CreateSessionID(oHTTPContext) Dim bIsRedir As Boolean = False Dim bIsAdd As Boolean = False oSessionIdManager.SaveSessionID(oHTTPContext, sNewId, bIsRedir, bIsAdd) Dim oAppContext As HttpApplication = HttpContext.Current.ApplicationInstance Dim oModules As HttpModuleCollection = oAppContext.Modules Dim oSessionStateModule As SessionStateModule = _ DirectCast(oModules.Get("Session"), SessionStateModule) Dim oFields() As FieldInfo = _ oSessionStateModule.GetType.GetFields(BindingFlags.NonPublic Or _ BindingFlags.Instance) Dim oStore As SessionStateStoreProviderBase = Nothing Dim oRqIdField As FieldInfo = Nothing Dim oRqItem As SessionStateStoreData = Nothing Dim oRqLockIdField As FieldInfo = Nothing Dim oRqStateNotFoundField As FieldInfo = Nothing For Each oField As FieldInfo In oFields If (oField.Name.Equals("_store")) Then oStore = DirectCast(oField.GetValue(oSessionStateModule), _ SessionStateStoreProviderBase) End If If (oField.Name.Equals("_rqId")) Then oRqIdField = oField End If If (oField.Name.Equals("_rqLockId")) Then oRqLockIdField = oField End If If (oField.Name.Equals("_rqSessionStateNotFound")) Then oRqStateNotFoundField = oField End If If (oField.Name.Equals("_rqItem")) Then oRqItem = DirectCast(oField.GetValue(oSessionStateModule), _ SessionStateStoreData) End If Next If oStore IsNot Nothing Then Dim oLockId As Object = Nothing If oRqLockIdField IsNot Nothing Then oLockId = oRqLockIdField.GetValue(oSessionStateModule) End If If (oLockId IsNot Nothing) And (Not String.IsNullOrEmpty(sOldId)) Then oStore.ReleaseItemExclusive(oHTTPContext, sOldId, oLockId) oStore.RemoveItem(oHTTPContext, sOldId, oLockId, oRqItem) End If oRqStateNotFoundField.SetValue(oSessionStateModule, True) oRqIdField.SetValue(oSessionStateModule, sNewId) End If


Me gustaría compartir mi magia. En realidad, no, aún no es mágico. Deberíamos probar y evolucionar más el código. Solo probé estos códigos en-cookie, modo de sesión InProc. Coloque estos métodos dentro de su página y llámelos a donde necesite que se regenere el ID (configure su aplicación web como Confianza total):

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); }

He estado investigando el código fuente .NET (que estaba disponible en http://referencesource.microsoft.com/netframework.aspx ), y descubrí que no hay forma de que pueda regenerar SessionID sin hackear las funciones internas del mecanismo de administración de la sesión. Así que lo hago: piratear los campos internos de SessionStateModule, por lo que guardará la sesión actual en una nueva ID. Quizás el objeto HttpSessionState actual todavía tenga el Id anterior, pero AFAIK el SessionStateModule lo ignoró. Solo usa el campo _rqId interno cuando tiene que guardar el estado en alguna parte. He intentado con otros medios, como copiar SessionStateModule en una nueva clase con una funcionalidad regenerada de ID, (estaba planeando reemplazar SessionStateModule con esta clase), pero fallado porque actualmente tiene referencias a otras clases internas (como InProcSessionStateStore). La desventaja de la piratería mediante el uso de la reflexión es que debemos establecer nuestra aplicación en ''Confianza total''.

Ah, y si realmente necesitas la versión VB, prueba estos:

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


Para MVC4 tenga este código:

System.Web.SessionState.SessionIDManager manager = new System.Web.SessionState.SessionIDManager(); HttpContext Context = System.Web.HttpContext.Current; 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)System.Web.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);