【问题标题】:For what design reason is Asp.Net Core SessionKey different than the SessionId?Asp.Net Core SessionKey 与 SessionId 不同的设计原因是什么?
【发布时间】:2021-05-20 21:00:29
【问题描述】:

一些背景

在 asp.net core 中使用 SqlServer 存储会话时,奇怪的是 SqlServer 表中的Id 列被设置为sessionKey 的值,这是由SessionMiddleware 生成的Guid。我说的很奇怪,因为有一个SessionId,但表中的Id 没有设置为那个,它设置为SessionKey。 (不是我编的)

用于表中IdsessionKey 也是加密并放置在会话cookie 中的值。这是SessionMiddleware的代码:

 var guidBytes = new byte[16];
 CryptoRandom.GetBytes(guidBytes);
 sessionKey = new Guid(guidBytes).ToString();
 cookieValue = CookieProtection.Protect(_dataProtector, sessionKey);
 var establisher = new SessionEstablisher(context, cookieValue, _options);
 tryEstablishSession = establisher.TryEstablishSession;
 isNewSessionKey = true;

然而,SessionId 是由以下代码行中的DistributedSession object 生成的Guid

_sessionId = new Guid(IdBytes).ToString();

有趣的是,ISession 接口为SessionId 提供了一个属性,但没有为SessionKey 提供一个属性。因此,在代码中访问 SessionIdSessionKey 通常要容易得多,例如当您可以访问 HttpContext 对象时。

如果您愿意,这使得很难将会话与数据库记录匹配。 stackoverflow 上的另一位用户也注意到了这一点 How to Determine Session ID when using SQL Sever session storage

为什么?

我想知道为什么系统会这样设计?为什么SessionIdSessionKey 不一样?为什么要使用两个不同的Guids?我问是因为我正在创建自己的ISession 实现,并且我很想在我的实现中使用SessionKey 作为SessionId,以便更容易将数据库中的记录与会话匹配。那会是个坏主意吗?为什么不想DistributedSession 对象以这种方式设计,而不是生成与SessionKey 不同的SessionId?我能想到的唯一原因可能是试图通过混淆数据库记录与其所属会话之间的链接来提高安全性。但总的来说,安全专家并不认为通过混淆来实现安全是有效的。所以我想知道为什么要实施这样的设计?

【问题讨论】:

    标签: sql-server security session cookies asp.net-core-mvc


    【解决方案1】:

    我还在 GitHub https://github.com/aspnet/Session/issues/151#issuecomment-287894321 上发布了这个问题,以尝试得到答案。

    @Tratcher 在那里回答了这个问题,所以我将他的答案粘贴在下面,这样它也可以在 stackoveflow 上找到。

    生命周期不同。会话(和 SessionId)的真实生命周期由服务器控制。 SessionKey 存储在 cookie 中,并在客户端上存在不确定的时间。如果会话在服务器上过期,然后客户端使用旧 SessionKey 发送新请求,则会创建一个具有新 SessionId 的新会话实例,但使用旧 SessionKey 存储,这样我们就不必发出新的 cookie。

    换句话说,不要依赖于你无法控制的事情。客户端可以无限期地保留和重放他们的 SessionKey,但它是服务器来决定这是否真的仍然是同一个会话。

    【讨论】:

      【解决方案2】:

      如果有人需要在 asp.net core 3 中获取 sessionkey

      1. 为 IDataProtector 添加 DI(重要!创建保护器时应为 nameof(SessionMiddleware))

        public IDataProtector _dataProtector;
        
        public TestController( IDataProtectionProvider dataProtectionProvider )
        {
            _dataProtector = dataProtectionProvider.CreateProtector(nameof(SessionMiddleware));
        }
        
      2. 创建将为会话 cookie 获取适当值的方法

        private string Pad(string text)
        {
            var padding = 3 - ((text.Length + 3) % 4);
            if (padding == 0)
            {
                return text;
            }
            return text + new string('=', padding);
        }
        
      3. 使用它

        public ActionResult TestSession(  )
        {
        
            var protectedText = HttpContext.Request.Cookies[ ".AspNetCore.Session" ];
        
            var sessionKey = "";
            var protectedData = Convert.FromBase64String(Pad(protectedText));
            if (protectedData == null)
            {
                sessionKey = string.Empty;
            }
        
            var userData = _dataProtector.Unprotect(protectedData);
            if (userData == null)
            {
                sessionKey = string.Empty;
            }
        
            sessionKey = Encoding.UTF8.GetString(userData);
        
            return Content( sessionKey );
        }
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-02-20
        • 2018-04-16
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多