在当前HTTPContext中生成新的ASP.NET会话

Rab*_*bid 26 asp.net session-state sessionid httpsession

由于对我们的一些产品进行了渗透测试,当时看起来很容易解决的"容易"问题变得非常棘手.

当然不应该这样,我的意思是,为什么只为当前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
Run Code Online (Sandbox Code Playgroud)

它对请求的其余部分工作正常,并正确地将自己标识为新会话(例如,HTTPContext.Current.Session.SessionID返回新生成的会话标识符).

然后惊喜的是,当下一个请求命中服务器时,HTTPContext.Session(一个HTTPSessionState对象)用正确的标识自己SessionID,但是IsNewSession设置为True,并且为空,丢失了在前一个请求中设置的所有会话值.

因此,HTTPSessionState从初始请求中删除前一个对象,这里有一个事件处理程序,一个回调函数,处理跨请求持久化会话数据的东西,或者只是我缺少的东西,必须有一些特殊的东西?

有人分享任何魔力吗?

Yud*_*ama 36

我想分享我的魔力.实际上,不,它还不是神奇的......我们应该更多地测试和改进代码.我只在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);
}
Run Code Online (Sandbox Code Playgroud)

我一直在挖掘.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
Run Code Online (Sandbox Code Playgroud)

  • 伙计,你是英雄 (3认同)

Dub*_*Dub 5

如果您具有安全意识并希望此答案的 C# 版本删除旧字段,请使用以下内容。

private static void RegenerateSessionId()
{

    // Initialise variables for regenerating the session id
    HttpContext Context = HttpContext.Current;
    SessionIDManager manager = new SessionIDManager();
    string oldId = manager.GetSessionID(Context);
    string newId = manager.CreateSessionID(Context);
    bool isAdd = false, isRedir = false;

    // Save a new session ID
    manager.SaveSessionID(Context, newId, out isRedir, out isAdd);

    // Get the fields using the below and create variables for storage
    HttpApplication ctx = HttpContext.Current.ApplicationInstance;
    HttpModuleCollection mods = ctx.Modules;
    SessionStateModule ssm = (SessionStateModule)mods.Get("Session");
    FieldInfo[] fields = ssm.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
    SessionStateStoreProviderBase store = null;
    FieldInfo rqIdField = null, rqLockIdField = null, rqStateNotFoundField = null;
    SessionStateStoreData rqItem = null;

    // Assign to each variable the appropriate field values
    foreach (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;
        if (field.Name.Equals("_rqItem")) rqItem = (SessionStateStoreData)field.GetValue(ssm);
    }

    // Remove the previous session value
    object lockId = rqLockIdField.GetValue(ssm);
    if ((lockId != null) && (oldId != null))
        store.RemoveItem(Context, oldId, lockId, rqItem);

    rqStateNotFoundField.SetValue(ssm, true);
    rqIdField.SetValue(ssm, newId);
}
Run Code Online (Sandbox Code Playgroud)