asp.net - 在当前 HTTPContext 中生成新的 ASP.NET session

标签 asp.net session-state sessionid httpsession

对我们正在筹备中的一些产品进行渗透测试的结果是,当时看起来“容易”解决的问题变成了一个棘手的问题。

当然不是说它应该,我的意思是为什么只是 为当前 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/

相关文章:

asp.net - DropDownList 的编辑器模板

c# - 在自定义 IValueProvider ASP.NET MVC 5.2.3 中获取 List<T> 的值

c# - 是否可以不指定工作表名称和列?

node.js - nodejs + express + appfog img 资源的不同 session

asp.net - 获取 session cookie名称

c# - Linq 查询给出不适当的输出

asp.net - 使用 Cookie 获取 Web session 状态 - 有哪些陷阱?

django - 登录后保留 Django session 数据吗?

php - 警告 : session_start() failed: No such file or directory

security - 我使用 guid 作为我的 Web 应用程序的 session ID,安全吗