将 Auth-Token 存储在 Cookie 或 Header 中?

信息安全 验证 饼干 休息 api
2021-09-05 02:26:49

我确实了解标头是在 REST 调用中将身份验证令牌从受信任系统传输到另一个系统的“更清洁”解决方案。但是,当您使用客户端 JavaScript 代码时,世界对我来说看起来就不同了。

Cookie 可以标记为“仅限 http”,因此无法轻易被 JavaScript 窃取。标头甚至必须由 JavaScript 设置,因此身份验证令牌必须可以从 JavaScript 中访问。但是,人们使用 auth-headers 将他们的 auth-token 从不受信任的客户端 JavaScript 提交到服务器。

从古老的“使用带有 http-only 和安全标志的 cookie”到“让 JavaScript 处理身份验证令牌”有什么变化?或者正确的方法应该是“在客户端,使用 cookie,一旦你进入受信任的世界,切换到 auth-header”?

PS:我知道类似问题有很多答案,但我认为我的问题是从不同的角度“改变了什么,不同了”。

3个回答

基于 Cookie 的身份验证

优点

  1. HttpOnly 标志:可以使用HttpOnly标志创建会话 cookie,该标志可以保护 cookie 免受恶意 JavaScript(XSS-Cross-Site Scripting)的影响。

  2. 安全标志:可以使用安全标志创建会话 cookie,以防止 cookie 通过未加密的通道传输。

缺点

  1. CSRF : Cookie 易受 CSRF 攻击,因为第三方 cookie 默认发送到导致 CSRF 漏洞利用的第三方域。

  2. 性能和可扩展性:基于 Cookie 的身份验证是一种有状态的身份验证,因此服务器必须将 cookie 存储在文件/数据库中以维护所有用户的状态。随着用户群的增加,后端服务器必须维护一个单独的系统来存储会话 cookie。

基于令牌的身份验证:

优点

  1. 性能和可扩展性:令牌包含元数据及其签名值(用于防篡改)。它们是独立的,因此不需要在服务器上维护状态。当需要扩展时,这会提高性能,从而提高可扩展性。

  2. CSRF:与基于 cookie 的身份验证不同,基于令牌的身份验证不易受到跨站点请求伪造的影响,因为默认情况下令牌不会发送到第三方 Web 应用程序。

缺点

  1. XSS:由于会话令牌存储在浏览器的本地数据存储中,并且可以被同域的 JS 访问。因此,与基于 cookie 的身份验证中可用的 HTTPOnly 安全标志不同,没有选项可以保护会话标识符免受 XSS 攻击。

结论

如前所述,这两种机制各有优缺点。在当前的应用程序开发框架时代,XSS 和 CSRF 等缺点由底层框架本身处理,因此我觉得毫无疑问这是一个明确的权衡由开发人员和利益相关者做出决定。

公认的答案是将基于会话的身份验证混为一谈——会话在后端数据库中维护,并且使用 cookie 是有状态的,cookie 是一种传输机制,因此优缺点存在缺陷。

至于身份验证令牌是否应该存储在 cookie 或标头中,这取决于客户端。如果客户端是另一个 REST api,那么通过标头传递它是有意义的。

如果客户端是浏览器,您可以将令牌存储在本地/会话存储中,然后通过标头发送令牌(如接受的答案所说),但正如您所提到的 - 这有漏洞并且不推荐(在此处查看更多信息:https ://auth0.com/docs/security/store-tokens )。

如果客户端是 SPA,您可以将令牌存储在内存中 - 这可能是最安全的选择,但是您将需要在页面之间检索新令牌。

如果您需要页面之间的持久性,“老式方式”可能仍然是最好的选择 - 前提是您的 cookie 是仅 http 的、安全的,并且您已经实现了 csrf 保护(尽管由于同一站点,这可能很快就没有必要了财产)。如果您确实实施了 csrf 保护,您将获得“基于无 cookie 令牌的身份验证”的所有好处以及针对 XSS 的额外保护。

公认的答案是完全错误的!

请不要混合使用 Cookie、Token、Stateful、Stateless。很多人认为 Cookie == 有状态。不,这是完全错误的!

有状态 == 基于会话 -> 您将数据存储在服务器和客户端上,只需持有 session_id、opaque_token。

无状态 -> 您不在服务器上存储任何内容,所有数据都嵌入到令牌中,客户端持有令牌并发送到服务器进行身份验证/授权。Token 可以是 JWT、PASETO 或任何格式。

Cookie 只是交通工具。您可以使用 Cookie 或 Authorization Header 发送 token/session_id/opaque_token。