会议的“秘密”选项是什么?

我对密码学一窍不通,我想知道会话秘密是什么。

我看到这样的代码:

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

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

80148 次浏览

是的,你应该改变它。连接中的会话秘密只用于 计算散列表。如果没有字符串,对会话的访问基本上将被“拒绝”。看看 连接文件,应该会有点帮助。

这个秘密被用来与 HMAC 对话:

Https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#l256

然后,通过检查指纹和 hash 的 secret,保护会话不受会话劫持攻击:

Https://github.com/senchalabs/connect/blob/master/lib/middleware/session.js#l281-l287

这个答案的动机

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

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

这个秘密防止什么?

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

你如何防止会话劫持?

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

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

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

express-session的秘密是做什么的?

Express 会话中间件... 通过会话 ID 和 secret 的组合计算散列。由于计算散列需要拥有秘密,因此攻击者无法在不猜测秘密(或只是试图猜测散列)的情况下生成有效的会话 ID。

因此,这个秘密被用来创建一个长且随机的散列。如果会话 ID 已经足够长且随机,那么以这种方式使用 secret 在很大程度上是多余的。正如其他用户所指出的那样,在一天结束时,攻击者只是在猜测一个冗长而随机的问题,而不是另一个。

但是不要这么快就否定散列的使用!

express-session是一个公共软件包

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

如果一个没有经验的用户定义了他们自己的不安全的会话 ID 生成器(例如,上面讨论过的顺序生成器) ,散列将会改善这个安全缺陷。

正如提交人指出的 其他地方:

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

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

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

还有其他好处

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

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

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

虽然 cookie 带有过期策略,但是没有办法确保它实际上得到遵守。(...)一个常见的最佳实践是在每个颁发的凭证中包含一个时间戳,这可以很简单地为随机生成的会话 ID 添加一个时间戳后缀。但是,为了依赖这个时间戳,我们必须能够验证它是否经过了调整,并且实现这一点的方法是使用散列或签名。(...)将时间戳添加到会话 id 允许服务器快速处理过期的会话,而不必进行昂贵的数据库查找。

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

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

结语

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

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

再一次,我愿意把这篇文章的一切都归功于 这个答案。我只是一个好奇的旁观者!