会话的"秘密"选项是什么?

Har*_*rry 99 session connect node.js

我对密码学一无所知.我想知道会议的秘密是什么.

我看到这样的代码:

app.use(express.session({
  store: mongoStore({
    url: app.set('db-uri')
  }),
  secret: 'topsecret'
}));
Run Code Online (Sandbox Code Playgroud)

秘密是什么,我应该改变它吗?

Hac*_*tly 76

是的,你应该改变它.connect中的会话密钥仅用于计算哈希值.没有字符串,访问会话基本上将被"拒绝".看看连接文档,这应该有所帮助.

  • 你不仅可以改变它,而且你应该改变它. (40认同)
  • @FRD我的观点是你不应该保留像`topsecret`这样的默认值.秘密应该是随机字符串.理想情况下,如果发现它,您也会定期更改它.但是,这需要支持秘密轮换,因此您不会立即使现有会话无效.也就是说,两个会话秘密应该被认为是同时有效的.据我所知,Express目前不支持轮换秘密. (9认同)
  • @MichaelMior自1.11.0以来的快速会议支持秘密轮换.从文档:"如果提供了一系列秘密,只有第一个元素将用于签署会话ID cookie,而在验证请求中的签名时将考虑所有元素." (有关详细信息,请参阅[expressjs/session#127](https://github.com/expressjs/session/issues/127).) (7认同)
  • @MichaelMior,多久一次? (3认同)
  • 这里问了两个问题:“秘密是什么”和“我应该改变它”。只回答了后一个问题。 (3认同)
  • @RishabhPoddar 可以调整旋转频率和阵列深度以达到折衷方案。假设密钥每天都会更改,并且数组长度为 5。那么您将允许攻击者使用密钥访问最多 5 天。此外,当最后一个密钥轮换时,您只会使已经存在 5 天的会话失效(可能问题不大,因为会话可能会被刷新)。密钥重置时间调整会话失效的粒度。数组长度调整一次使用的键的数量。它们一起调整密钥的有效时间。 (2认同)
  • 另请注意,您应该**避免在源代码中对秘密进行硬编码**!相反,您通常将其设置为环境变量并通过例如“process.env.SESSION_SECRET”访问它([请参阅 GitHub 上的此评论](https://github.com/expressjs/session/issues/524#issuecomment- 346570923)) (2认同)

sub*_*ack 20

该秘密用于哈希与HMAC的会话:

https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#L256

然后通过使用秘密检查带有散列的散列的指纹来保护会话免受会话劫持:

https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#L281-L287

  • 这个秘密是哈希的一个盐,这使得某人更难以:1.解密一个网络钓鱼的cookie,2.通过模仿用户欺骗会话,因为他们没有秘密(盐)他们不能产生适当的会话ID. (8认同)
  • 由于这是一个3年前的答案,这两个链接都是无效的. (7认同)
  • @mattdlockyer这不会保护您免受会话劫持.为什么攻击者会尝试解密cookie呢?如果攻击者拥有cookie,则他/她已经拥有完全访问权限,直到会话结束.我的意思是,不像人们将用户的密码存储在cookie中,这将是荒谬的.像jwt这样的东西几乎总是应该避免. (4认同)
  • 但是,散列如何防止会话劫持?如果攻击者有会话cookie,那么他们也没有哈希值吗?如果攻击者*没有*拥有cookie,那么秘密哈希如何让它更难猜测(而不是只有一个更长的随机会话ID)? (3认同)

Sha*_*ian 16

这个答案的动机

其他答案解决了“我应该更改它吗?” 并提供“这是什么?”的表面解释。作为一个刚刚开始使用的人express-session,我很好奇,在我的阅读中发现,对于拥有这样的秘密是否有价值以及价值有多大,存在很多分歧。

许多讨论这个话题的人似乎都是像我这样的安全新手。然而,我发现这个答案,全面解释了秘密的预期效果和一些可能性。你应该阅读整个答案,但我会尝试总结一下。

这个秘密可以防止什么?

这里讨论的攻击类型是会话劫持。通常,这涉及攻击者获取有效用户的会话 ID,从而能够模拟该用户的会话并允许攻击者访问信息或代表受害者进行操作。

如何防止会话劫持?

一个好的开始是使用足够长且随机的会话 ID,因为它会抑制攻击者猜测 ID 的能力。正如另一个答案的作者指出的:

同样重要的是,会话 ID 不是使用可预测的算法(例如计数器)生成的,因为如果存在这种逻辑,攻击者就不再猜测而是生成会话 ID。

举个例子:如果攻击者发现您的会话 ID 是连续的(例如 1、2、3),那么如果他们发现会话 ID 为 2,那么他们可以合理地假设 1 和 3 也是会话 ID。

express-session的秘密有什么作用?

Express 会话中间件...根据会话 ID 和秘密的组合计算哈希值。由于计算哈希值需要拥有密钥,因此攻击者在不猜测密钥(或只是尝试猜测哈希值)的情况下将无法生成有效的会话 ID。

因此,该秘密用于创建一个长且随机的哈希值。如果会话 ID 已经足够长且随机,那么以这种方式使用秘密在很大程度上是多余的。正如其他用户指出的那样,归根结底,攻击者只是猜测一个长而随机的内容,而不是另一个。

但不要这么快就放弃哈希的使用!

express-session是一个公共包

Express 会话中间件的一个重要功能是支持用户生成的会话 ID。这允许开发人员在现有环境中部署中间件,其中会话 ID 由可能驻留在完全不同平台上的现有实体生成。如果不向用户提供的会话 ID 添加哈希,构建安全系统的负担就会从专家(模块作者)转移到用户(可能是安全新手)。应用哈希是比强制使用内部会话 ID 生成器更好的方法。

如果没有经验的用户定义了他们自己的不安全会话 ID 生成器(例如,如上所述的连续的东西),则对其进行散列将改善该安全缺陷。

正如作者在别处指出的那样:

此外,这是一个通用模块,假设其核心需求是广泛的用户。它绝对必须假设有些人会不好地使用它(例如增加 ids)并适应这一点。这也是为广大受众构建模块时的常见做法。

不要把所有鸡蛋放在同一个篮子里

使用秘密进行散列是一层安全性,可以帮助掩盖其他层中的缺陷。如果您的随机会话 ID 生成器存在可被利用的错误怎么办?如果编码时不小心使用了RNG.pseudoRandomNumber()而不是怎么办?RNG.strongRandomNumber()如果您的依赖项之一损坏或受到损害怎么办?哈希再次有助于修复这些缺陷。

还有其他好处

您可以检测过期/未分配的 ID 和无效(恶意生成)ID 之间的差异:

通过在会话 ID 中包含完整性组件(通过散列或签名),服务器可以立即区分过期会话、未分配会话 ID 和无效会话。即使您只记录无效的身份验证尝试(您应该这样做),您也会希望以不同于无效会话的方式记录过期会话。

您可以在 ID 中构建防篡改时间戳:

虽然 Cookie 带有过期政策,但无法确保实际遵守该政策。(...) 常见的最佳实践是在颁发的每个凭证中包含时间戳,这可以像向随机生成的会话 ID 添加时间戳后缀一样简单。然而,为了依赖这个时间戳,我们必须能够验证它没有被篡改,并且实现这一点的方法是使用哈希或签名。(...)向会话 ID 添加时间戳允许服务器快速处理过期会话,而无需进行昂贵的数据库查找。

如果出现问题,您可以立即使许多 ID 失效:

由于生成哈希或签名需要服务器端机密或密钥,因此替换机密将立即导致所有会话 ID 验证失败。通过对不同类型的会话 ID 使用不同的秘密,可以隔离和管理整个会话类别。如果没有这样的机制,应用程序本身必须对每个会话的状态做出计算决策或执行大量数据库更新。

综上所述

拥有秘密(并使用它进行散列)提供了许多好处:

  1. 它保护用户免受自身伤害
  2. 它增加了额外的防御层
  3. (使用自定义会话 ID 生成器)它允许检测恶意行为
  4. (使用自定义会话 ID 生成器)它允许将时间戳捆绑到 ID 中
  5. 它提供了一个终止开关

再次,我想将这篇文章中的所有内容归功于这个答案。我只是一个好奇的旁观者!