对我们正在筹备中的一些产品进行渗透测试的结果是,当时看起来“容易”解决的问题变成了一个棘手的问题。
当然不是说它应该,我的意思是为什么只是 为当前 HTTPContext
生成一个全新的 session 这么难?奇怪!无论如何 - 我写了一个厚颜无耻的小实用程序类来“做它”:
(为代码格式/突出显示/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
它对请求的其余部分工作正常,并正确地将自己标识为新 session (例如
HTTPContext.Current.Session.SessionID
返回新生成的 session 标识符)。令人惊讶的是,当下一个请求到达服务器时,
HTTPContext.Session
(一个 HTTPSessionState
对象)用正确的 SessionID
标识自己,但有 IsNewSession
设置为 True
, 并且为空,丢失在上一个请求中设置的所有 session 值。所以之前的
HTTPSessionState
肯定有什么特别之处从初始请求中删除的对象,这里的事件处理程序,那里的回调,处理跨请求保存 session 数据的东西,或者只是我缺少的东西?有人有什么魔法可以分享吗?
最佳答案
我想分享我的魔法。实际上,不,它还没有神奇。我们应该更多地测试和改进代码。
我只在 with-cookie、InProc session 模式下测试了这些代码。将这些方法放在您的页面中,并在需要重新生成 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 中找到),并发现如果不破解 session 管理机制的内部结构,我就无法重新生成 SessionID。所以我就是这样做的 - 破解 SessionStateModule 内部字段,这样它就会将当前 session 保存到一个新的 ID 中。也许当前的 HttpSessionState 对象仍然具有以前的 Id,但 SessionStateModule AFAIK 忽略了它。当它必须在某处保存状态时,它只使用内部 _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
关于asp.net - 在当前 HTTPContext 中生成新的 ASP.NET session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1368403/