在目前 HTTPContext 中生成新的 ASP.NET 會話
由於對我們正在開發中的一些產品進行了滲透測試,當時看起來“容易”解決的問題變成了棘手的問題。
不是說它當然應該,我的意思是為什麼只**為目前生成一個全新的會話
HTTPContext**如此困難?奇怪!不管怎樣——我寫了一個厚臉皮的小實用類來“做它”:(為程式碼格式化/突出顯示/ Visual Basic道歉,我一定做錯了什麼)
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它適用於請求的其餘部分,並正確地將自己標識為新會話(例如
HTTPContext.Current.Session.SessionID,返回新生成的會話標識符)。令人驚訝的是,當下一個請求到達伺服器時,
HTTPContext.Session(一個HTTPSessionState對象)將自己標識為正確的SessionID,但已IsNewSession設置為True,並且為空,失去了前一個請求中設置的所有會話值。因此,從初始請求中刪除的前一個對像一定有什麼特別之處
HTTPSessionState,這裡有一個事件處理程序,那裡有一個回調,處理跨請求持久化會話數據的東西,或者只是我缺少的東西?有人有什麼魔法可以分享嗎?
我想分享我的魔法。實際上,不,它還沒有神奇。我們應該更多地測試和改程序式碼。我只在 with-cookie、InProc 會話模式下測試了這些程式碼。將這些方法放在您的頁面中,並在您需要重新生成 ID 的地方呼叫它(請將您的 Web 應用程序設置為完全信任):
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); }我一直在探勘 .NET 原始碼(可在<http://referencesource.microsoft.com/netframework.aspx>),並發現如果不破解會話管理機制的內部結構,我就無法重新生成 SessionID。所以我就是這麼做的——破解 SessionStateModule 內部欄位,所以它會將目前的 Session 保存到一個新的 ID 中。也許目前的 HttpSessionState 對象仍然具有以前的 Id,但是 AFAIK SessionStateModule 忽略了它。當它必須在某處保存狀態時,它只使用內部 _rqId 欄位。我嘗試了其他方法,比如將 SessionStateModule 複製到具有重新生成 ID 功能的新類中(我打算用這個類替換 SessionStateModule),但失敗了,因為它目前引用了其他內部類(如 InProcSessionStateStore)。使用反射進行黑客攻擊的缺點是我們需要將我們的應用程序設置為“完全信任”。
哦,如果你真的需要 VB 版本,試試這些:
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