会话 ID 应该在 cookie 中加密吗?

Should session id be encrypted in cookie?

在单页应用中:

我想使用 httpOnly/Secure cookie 来验证 Bearer 令牌没有从本地存储中被盗。

换句话说,cookie 和不记名令牌必须在被视为有效之前出示并交叉检查。

例如:

用户使用 Username/Password 成功登录。

创建了一个 Jwt Bearer 令牌并包含会话 ID 12345。

此外,cookie 的格式为 jwt 并已签名,并包含会话 ID 为 12345 的声明。

现在,当使用令牌和 cookie 发出 ajax 请求时,将比较会话 ID。如果匹配,则请求完成。

这安全吗?还是应该在 cookie 或令牌上加密会话 ID?

根据您告诉我们的内容,您的设置可能安全,也可能不安全。您需要提供更多详细信息才能让我们确定。

例如,根据您告诉我们的内容,您基本上是在向用户颁发两个不同的不记名令牌,表示 "the bearer of this token is allowed to access session 12345",其中一个令牌存储在 httpOnly cookie 中和 LocalStorage 中的另一个,并且仅当两个令牌都存在且有效并且它们相互匹配时才允许访问。

但是,您的描述并未明确说明 LocalStorage 令牌是否也可以用作 cookie 令牌,反之亦然。如果可能的话,捕获其中一个令牌的攻击者可以简单地在同一个 Ajax 请求中两次提交相同的捕获令牌,一次在 cookie 中,一次在请求参数中,因此看起来有效。

此外,仅仅检查请求中的两个令牌是否相同可能是不够的,因为攻击者可能能够捕获例如同一会话的两个不同的有效 LocalStorage 令牌。相反,要防止此类攻击,您需要做的是在构成令牌的签名数据中包含某种 令牌类型标识符 (例如,只是 type: "cookie" 与.type: "param") 并验证每个令牌的类型是否与它们呈现给服务器的方式实际匹配。

或者,您可以为 cookie 令牌和参数令牌使用两个不同的签名密钥;这样,将令牌从 LocalStorage 复制到 cookie 中(反之亦然)会自动使签名无效。

就是说,只要您以某种方式确保每种类型的令牌仅在通过适当的渠道呈现时才有效,您的设置至少 不亚于 仅使用一个令牌。它还应该防止某些类型的额外攻击,例如 CSRF 攻击(它可以允许攻击者使用合法用户的 cookie 发出恶意请求)和某些类型的 JS 注入攻击(这可能会危及用户的 LocalStorage,但不会危及他们的 cookie ).

但是,我们无法真正判断这些攻击是否是与您的应用程序相关的威胁,以及是否可能存在您的方案不足以足以保护的其他攻击反对。特别是,虽然您的方案应该足以抵御 危害 LocalStorage 的攻击,但值得注意的是,大多数可以做到这一点的攻击也允许攻击者做其他事情,例如从用户的浏览器中发出他们自己的 Ajax 请求(这会阻碍您的计划)。

也就是说,至少您的方案(如果实施正确)提供了 CSRF 保护,这是一个有用的东西。它是否提供更多的东西是另一回事。

(在任何情况下,通常都不需要加密会话 ID 或任何包含它的令牌,只要攻击者不能仅仅通过知道会话 ID 来做任何恶意的事情。如果他们可以,那么有一个像“12345”这样的会话 ID 无论如何都不是一个好主意,因为攻击者很容易尝试从 0 到 999999 的所有会话 ID。)