为客户端-服务器关系选择会话 ID 算法

信息安全 加密 密码 验证 哈希 会话管理
2021-08-18 08:06:02

我正在开发一个具有客户端-服务器关系的应用程序,但我无法确定确定会话标识符的算法。我的目标是限制冒名顶替者获取其他用户的私人数据。


我正在考虑两种选择:

选项 1:生成一个随机的 32 个字符的十六进制字符串,将其存储在数据库中,并在客户端登录成功后将其从服务器传递给客户端。客户端然后存储此标识符并在以后对服务器的任何请求中使用它,服务器将与存储的标识符进行交叉检查。

选项 2:从会话的开始时间和客户端的登录用户名和/或哈希密码的组合创建一个哈希,并将其用于所有未来对服务器的请求。会话哈希将在第一次请求时存储在数据库中,并针对来自客户端的任何未来请求进行交叉检查。

其他信息:多个客户端可以同时从同一个 IP 连接,并且两个客户端不应具有相同的会话标识符。


问题:关于我对每个选项的担忧(如下),这些选项中哪个是更好的方法?

我对第一个选项的担忧是标识符是完全随机的,因此可以偶然复制(尽管它是3.4 * 10 38中的 1 ),并用于“窃取”一个用户(也需要使用当时的客户)私人数据。

我对第二个选项的担忧是它有一个安全漏洞,即如果用户的哈希密码以某种方式被截获,整个会话哈希可能会被欺骗,并且用户的私人数据可能会被盗。

感谢您的任何和所有输入。

3个回答

会话标识符的基本概念是它是会话的一个短暂的秘密名称,是一种在服务器控制下(即在您的代码控制下)的动态关系。由您决定何时开始和停止会话。成功的会话标识符生成算法的两个安全特征是:

  1. 任何两个不同的会话都不应具有相同的标识符,具有压倒性的可能性。
  2. 在尝试随机标识符时以不可忽略的概率“命中”会话标识符在计算上不应该是可行的。

这两个属性是通过至少 16 个字节(32 个十六进制表示的字符)的随机会话 ID 实现的,前提是生成器是加密强 PRNG/dev/urandom在类 Unix 系统CryptGenRandom()上、Windows/Win32RNGCryptoServiceProvider上、.NET 上) ...)。由于您还将会话 ID 存储在数据库服务器端,因此您可以检查重复项,实际上您的数据库可能会为您执行此操作(您希望此 ID 作为索引键),但这仍然是浪费时间,因为概率非常低。考虑一下,每次你走出家门时,你都在赌自己不会被闪电击中。被闪电杀死的概率约为每天3*10 -10 (真的)。那是危及生命的风险,准确地说是你自己的生命。然而,你忽略了这种风险,却从未考虑过。那么,担心会话 ID 冲突的可能性要小几百万倍,而且如果它们发生也不会杀死任何人,这有什么意义呢?

在事物中抛出额外的哈希函数没有什么意义。正确应用的随机性已经为您提供了所需的所有独特性。增加的复杂性只会导致增加的弱点。

加密功能与您不仅希望拥有会话,而且还希望避免任何基于服务器的存储成本的场景相关;比如说,您在服务器上没有数据库。这种状态卸载需要MAC和可能的加密(有关详细信息,请参阅此答案)。

会话 ID 需要是加密强度随机且唯一的。如果攻击者可以猜出合法的会话 ID,他可能会冒充该用户。

选项 1 是您最好的选择,只要您使用正确的 CSPRNG,而不是rand()来自标准库的东西。使用类似选项 2 的东西并不安全,因为用户名和时间很容易被猜到或被暴力破解。

看看PHP 的会话 ID 生成器代码是如何工作的,您会看到一个哈希函数用于组合客户端的 IP 地址、当前时间(秒和微秒)以及来自 PHP 的线性一致性生成器 (LGC) 的一些值) RNG 作为基线。如果一个特定于操作系统的随机源可用,则进一步的熵将混合到该函数的 ID 中。如果没有可用的强熵源,这将提供合理的安全余量,但如果有,则提供强安全性。

会话标识符应该被签名然后你不必担心人们试图猜测会话ID。

还要检查冲突以确保您尚未泄露该标识符。