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

xyhw6mcr  于 12个月前  发布在  .NET
关注(0)|答案(7)|浏览(118)

由于对我们的一些产品进行了渗透测试,当时看起来是一个“容易”解决的问题,现在却变成了一个棘手的问题。
当然,这并不是说它应该这样做,我的意思是为什么仅仅为当前的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对象一定有什么特殊之处,这里有一个事件处理程序,那里有一个回调函数,处理跨请求持久化会话数据的东西,或者只是我遗漏了什么?
有谁有魔法要分享吗?

bxpogfeg

bxpogfeg1#

我想分享我的魔法。实际上,不,它还没有魔法。。我们应该测试和发展代码更多。我只在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忽略了它。当它必须在某个地方保存状态时,它只使用internal _rqId字段。我尝试过其他方法,比如将SessionStateModule复制到具有重新生成ID功能的新类中,(我计划用这个类替换SessionStateModule),但失败,因为它当前有对其他内部类的引用使用反射的缺点是我们需要将应用程序设置为“完全信任”。
哦,如果你真的需要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

vshtjzan

vshtjzan2#

如果您有安全意识,并且希望此答案的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);
}

字符串

ffdz8vbo

ffdz8vbo3#

正如Can Gencer所提到的- ReleaseItemExclusive不会从存储中删除旧会话,这会导致该会话最终过期并在Global. asax中调用Session_End。这给我们的生产带来了一个巨大的问题,因为我们正在清除Session_End中的线程标识,因此-用户会自发地失去线程上的身份验证。
所以下面是正确的代码,工作。

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

字符串

6tqwzwtp

6tqwzwtp4#

你有没有考虑过使用HttpSessionState.Abandon method?这应该会清除所有内容。然后启动一个新的会话,并使用上面代码中存储的所有项目填充它。
Session.Abandon();应该足够了。否则,如果它仍然很顽固,你可以尝试多打几个电话:

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

字符串

yebdmbv4

yebdmbv45#

你不能只设置:

<sessionState regenerateExpiredSessionId="False" />

字符串
在web.config中,然后使用Ahmad建议的解决方案?

dgsult0t

dgsult0t6#

登录asp.net后如何更改会话ID
对于那些现在正在搜索并看到所有这些反射黑客和正在与会话固定问题作斗争的人来说,进入asp.net创建新会话ID的唯一方法是伪造一个SessionIDManager,为您的登录页面返回null。这样ASP.NET就认为浏览器从未发送过cookie。
以下是步骤:

  • 创建一个CustomSessionIDManager,注意YourLoginController/LoginMethod
public class CustomSessionIDManager : ISessionIDManager
{
    private readonly SessionIDManager _sessionIDManager;

    public CustomSessionIDManager()
    {
        _sessionIDManager = new SessionIDManager();
    }

    public string CreateSessionID(HttpContext context)
    {
        return _sessionIDManager.CreateSessionID(context);
    }

    public string GetSessionID(HttpContext context)
    {
        var path = context.Request.Path.ToString();
        if (path.EndsWith("YourLoginController/LoginMethod"))
            return null;
        return _sessionIDManager.GetSessionID(context);
    }

    public void Initialize()
    {
        _sessionIDManager.Initialize();
    }

    public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIDReissue)
    {
        return _sessionIDManager.InitializeRequest(context, suppressAutoDetectRedirect, out supportSessionIDReissue);
    }

    public void RemoveSessionID(HttpContext context)
    {
        _sessionIDManager.RemoveSessionID(context);
    }

    public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded)
    {
        _sessionIDManager.SaveSessionID(context, id, out redirected, out cookieAdded);
    }

    public bool Validate(string id)
    {
        return _sessionIDManager.Validate(id);
    }
}```

- Put it on the `web.config`:

  

     <system.web>
           <sessionState sessionIDManagerType="CustomSessionIDManager" />
     </system.web>

Now it should return a new session for each login.

字符串

db2dz4w8

db2dz4w87#

对于MVC 4,请输入以下代码:

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

字符串

相关问题