为什么Session.Clear()-不起作用?

时间:2018-07-06 07:49:30

标签: c# asp.net-web-api .net-core .net-core-2.1

我正在使用.NET Core 2.1,并试图将Session用作身份验证的一部分。我期望发生的是:

  1. 人员登录
  2. 我设置了会话值
  3. 返回会话cookie
  4. 人员单击注销
  5. 我通过HttpContext.Session.Clear()清除了会话

然后,我试图伪造一种情况,即会话cookie已经从原始人那里窃取了,因此我向服务器创建了另一个请求,并期望会话中设置的值不存在。甚至在调用Session.Clear()之后,它看起来仍然保持不变。

代码:

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {     
          services.AddSession(options =>
          {
                options.IdleTimeout = TimeSpan.FromMinutes(10);
                options.Cookie.Name = SessionCookieName;
                options.Cookie.HttpOnly = true;
          });
    }



    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseSession();
    }

登录操作:

HttpContext.Session.SetInt32(SessionConstants.Key, value);

注销操作:

HttpContext.Session.Clear();

CheckLoginStatus操作:

 var sessionValue = HttpContext.Session.GetInt32(SessionConstants.Key);

测试解决问题的方法:

    var httpClientGenuineRequest = GetClient();
                var httpClientAttacker = GetClient();

                //Given
                var request = new LoginRequest()
                {
                   //filled properties
                };

                var loginResponse = await httpClientGenuineMember.PostAsync("urlToLoginAction", new JsonContent(request));
                AddResponseCookiesToHeaders(httpClientAttacker, loginResponse);

                await httpClientGenuineMember.PostAsync("urlToLogoutAction", new JsonContent(request));

                //When
                var response = await httpClientAttacker.GetAsync("urlToCheckStatusAction");

                //Here the actual result is true
                var actualResult = response.GetResult<bool>();

                //Then
                var expectedResult = false;

以上示例不完整。问题仅与会话值有关,因此我摆脱了所有其他身份验证代码以使其更加清晰。

在我看来,HttpContext.Session.Clear没有清除会话,或者该值存储在会话Cookie中(没有任何意义)?

此外,当我调试并检查密钥的Session值时,紧接Clear()之后,它为我提供了null值。但是,当我传递会话cookie并尝试读取该值时,它再次出现。

很明显,当Idle Timeout用完时,代码将按预期运行。在这段时间内,这听起来像是有一定的安全隐患。

任何帮助将不胜感激。

编辑:

根据帖子下方的评论,我尝试向其中添加Redis会话:

services.AddDistributedRedisCache(setup =>
            {
                setup.Configuration = "urlToRedisInstance";
                setup.InstanceName = "MySessionStateStore2";
            });

但行为完全相同。

2 个答案:

答案 0 :(得分:1)

原因是(听起来很荒谬)是因为您没有清除正确的会话变量。

根据Microsoft docs,当发生以下两种情况之一时,.net core 2.1中的会话结束:

  

在执行ISession.Clear时删除会话数据   或会话期满时被调用。

然后显示以下状态:

  

没有默认机制来通知应用代码客户端浏览器   已关闭,或者会话cookie被删除或过期   客户。

这告诉我们两件事:

1),如果您想使用会话已过期的最大次数,则必须自行修改 的机制,以在客户端会话过期时通知服务器或浏览器关闭。否则,即使关闭浏览器,您仍可能保留会话数据(这是一种荒谬的情况,但确实存在)。

2) ISession.Clear方法Microsoft.AspNetCore.Http命名空间的一部分,这意味着当您调用HttpContext.Session.Clear(); 时,您基本上可以清除一无所有。

正如我所说,这种情况可能很痛苦,但却是一个鲜活的事实,并且如果我们选择使用.net core 2.1和会话状态,我们的代码必须知道如何处理。

答案 1 :(得分:0)

挖掘代码后,我发现了问题:

问题出在我的测试中。我将登录请求响应cookie设置为“攻击者”的httpClient,而不是实际用户。结果,它没有得到Session Cookie,因此我的Session.Clear()实际上清除了新创建的会话,而不是登录过程中创建的会话。

正确的测试:

var httpClientGenuineRequest = GetClient();
                var httpClientAttacker = GetClient();

                //Given
                var request = new LoginRequest()
                {
                   //filled properties
                };

                var loginResponse = await httpClientGenuineMember.PostAsync("urlToLoginAction", new JsonContent(request));
                AddResponseCookiesToHeaders(httpClientGenuineMember, loginResponse); // THAT LINE MADE THE DIFFERENCE
                AddResponseCookiesToHeaders(httpClientAttacker, loginResponse);

                await httpClientGenuineMember.PostAsync("urlToLogoutAction", new JsonContent(request));

                //When
                var response = await httpClientAttacker.GetAsync("urlToCheckStatusAction");

                //Here the actual result is true
                var actualResult = response.GetResult<bool>();

                //Then
                var expectedResult = false;

Session.Clear()完全按预期工作。