我如何以及何时生成Node / Express cookie密钥?

时间:2017-11-03 22:51:27

标签: node.js mongodb session express cookies

我正在构建一个节点/快速应用程序并使用express-sessionmongo-connect模块存储我的会话并在重新启动时保留它们。

但是,每次重新启动服务器时仍会生成新的Cookie ID。我已将问题缩小到我的会话密码,这是一个随机生成的16个字符串,这是我的会话代码:

app.use(session({                                
    secret:  dbops.randomString(16),   // generate a 16 random char string
        saveUninitialized: false,
        resave: true,
        store: new MongoStore({ 
            db: thisDb,
            ttl: 14 * 24 * 60 * 60
         })
}));

问题在于我的randomString函数 - 当我用静态字符串替换它时,我的会话在服务器重启时仍然存在。我的 cookie秘密应该是什么?我应该选择一个长的随机字符串并存储在ENV变量中吗?

我认为我一般对字符串的用途感到困惑,因为我的Cookie SID似乎是随机生成的。

1 个答案:

答案 0 :(得分:14)

典型的会话cookie看起来像这样:

s%3Al3ozSdvQ83TtC5RvJ.CibaQoHtaY0H3QOB1kqR8H2A

它会比这长,但格式大致相同。

  • 开头的s%3A表示它是已签名的Cookie。
  • l3ozSdvQ83TtC5RvJ是会话ID(您可以通过检查服务器上的req.session.id来确认)。
  • CibaQoHtaY0H3QOB1kqR8H2A是签名。

您可以认为secret有点像用于生成签名的密码

通常,签名用于确认文本来自正确的位置。有人可能会篡改文本,但他们无法使用正确的签名对其进行签名,因为他们不知道secret。在cookie的上下文中,cookie的“起源”是服务器本身,因此它只是提供了一种方法来确认返回的cookie与发送的cookie相同。

但是,在会话ID的上下文中并不重要,因为如果有人更改了会话cookie,那只是意味着它们将不再登录,因为它与数据库中的id不匹配。那么为什么要打扰他们呢?

生成随机会话ID实际上非常困难。即使它看起来随机,但仍有可能让某人猜测它。签名可以帮助解决这个问题:当“随机”ID不是非常随机时,我们如何阻止某人猜测另一个用户的会话ID?

让我们把它带到一个假设的极端。我们不是使用随机会话ID,而是仅计数,因此第一个会话的标识为1,下一个会话为2,依此类推。有人可以很容易地猜出会话ID是什么,但这还不足以劫持会话。他们还需要能够签名,以获得类似的东西:

s%3A432.D5egYRj1G7sJyfbyB7jDh7Gf

此处的会话ID为432,并且不难猜测,但如果不知道签名,黑客就无法对该知识做任何事情。因此,即使您可以猜出“随机”部分,签名也很难猜测cookie值。

回到关于express-session的问题,顾名思义secret需要保密。它需要在重新启动之间保持不变,或者,正如您所注意到的,签名都将变为无效,旧会话cookie将全部被拒绝。群集中的节点之间也需要相同,因为无法保证请求始终会转到同一个节点。

您还应该了解可以使用的keys设置,而不是secret。使用keys可以更改用于生成签名的secret,而不会立即使所有现有会话无效。我们的想法是指定一组键(秘密)。只有第一个用于生成签名,但所有条目对于检查cookie上的传入签名是有效的。这个想法很简单,只要需要它们就可以将旧秘密包含在阵列中,然后一旦我们确信没有会话正在使用它们就可以删除它们。

  

我应该选择一个长的随机字符串并将其存储在ENV变量中吗?

差不多。它不一定要疯狂,但确实需要让人猜测。这有点像密码,但有一个优点,你不必记住它。理想情况下,您将生产中使用的secret保留在代码之外,使用环境变量将是实现此目的的一种方法。