JWT 可以用作 CSRF 令牌吗?

信息安全 csrf jwt
2021-09-06 14:02:16

对于提交表单的某个应用程序,我需要一个 CSRF 令牌POST理想情况下,我不想为每次提交进行数据库调用,以避免存储和数据库流量和延迟。为此,OWASP 的“CSRF 预防备忘单”说,

概述

加密令牌模式利用加密而非比较令牌验证方法。成功认证后,服务器使用仅在服务器上可用的唯一密钥生成由用户 ID、时间戳值和随机数组成的唯一 Token。此 Token 返回给客户端并嵌入到隐藏字段中。[…] 基于非 AJAX 表单的请求将隐式地将令牌保留在其隐藏字段中。收到此请求后,服务器使用用于创建 Token 的相同密钥读取和解密 Token 值。[…]

验证

在成功的令牌解密后,服务器可以访问解析的值,理想情况下以声明的形式。

对我来说,“验证”的第一行就像JWT的定义一样。我也不明白为什么需要加密令牌中的信息:看起来它只需要验证它来自服务器(而不是攻击者试图伪造 CSRF 令牌。)

加密 CSRF 令牌有什么特别的原因吗?如果没有,JWT 就足够了吗?

此外,上述令牌模式包括随机数。随机数的意义何在?(这个模式的重点是不存储任何状态服务器端。如果我不存储状态,我如何在验证期间以任何实质性方式使用随机数?)

我在这里追求 JWT 的主要原因是有不错的库支持,我可能迟早会想要它们进行身份验证,而且它主要让我远离实现加密的东西。

我对 JWT 的理解是,如果我有用于完整用户身份验证的 JWT,我可以将它们存储在 中localStorage,并在提交表单之前简单地将它们添加到带有 JS 的字段中。不幸的是,该应用程序使用基于 cookie 的身份验证,我现在无法更改该方面。

4个回答

TL;博士

如果在没有 Cookie 的情况下使用 JWT,则不需要 CSRF 令牌 - 但是!通过将 JWT 存储在 session/localStorage 中,如果您的站点存在 XSS 漏洞(相当常见),您将暴露您的 JWT 和用户身份。最好将csrfToken密钥添加到 JWT 并将 JWT 存储在带有securehttp-only属性集的 cookie 中。

阅读这篇文章,了解更多信息 https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage

您可以通过包含 xsrfToken JWT 声明使此 CSRF 保护无状态:

{ "iss": "http://galaxies.com", "exp": 1300819380, "scopes": ["explorer", "solar-harvester", "seller"], "sub": "tom@andromeda.com", "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e" }

因此,您需要将 csrfToken 存储在 local/sessionStorage以及JWT 内部(存储在仅 http 且安全的 cookie 中)。然后对于 csrf 保护,验证 JWT 中的 csrf 令牌是否与提交的 csrf-token 标头匹配。

无需加密令牌或包含随机数。CSRF 令牌的关键属性是攻击者无法预测它,并且与 cookie 不同,它不会被浏览器添加到每个请求中。存储在隐藏字段中的加密安全JWT满足这两个属性。

请注意,您需要使用其中包含用户唯一数据的 JWT。拥有非特定于用户的空或通用 JWT 不会为您提供安全性。

您可以将 JWT 用作 CSRF 令牌,但这会不必要地复杂:CSRF 令牌不需要包含任何声明,也不需要加密或签名。

对于 JWT 或 CSRF 令牌的用途可能存在误解(起初我也很困惑)。JWT 是一个访问令牌,用于身份验证。另一方面,CSRF 令牌用于保护用户不被欺骗发送伪造的经过身份验证的请求。当使用会话或 HTTP 基本身份验证或将 JWT 存储在 cookie 中时,这是必要的——任何由浏览器自动完成的身份验证。

如果您有这样的身份验证方案,请确保您

  • 使用正确的 HTTP 动词(GET 不能有副作用)
  • 在每个请求上生成一个新的 CSRF 令牌
  • 将 CSRF 令牌包含在标头中或作为每个 PATCH、POST、PUT 和 DELETE 请求的 HTTP 参数

例如,阅读Spring 如何处理 CSRF

请注意,将 JWT 存储在cookieorlocalStorage中并不是主要问题。将 JWT 存储在 acookie和 中一样好localStorage,只要服务器不在 cookie 标头中查找 JWT。如果您将 JWT 存储在名为的 cookie 中,token但仅在服务器端的Authorization: Bearer ...类型标头中接受它,那么您在 CSRF 中的安全性与存储在 中时一样安全localStorage,因为服务器端将忽略标头token中的发送Cookie

但是,要使其正常工作,您的 web 应用程序需要以使用 JavaScript 发送所有有效请求的方式构建,您的 JS 从调用的 cookie 中读取令牌token并将其作为Authorization: Bearer ...类型标头附加到传出请求。

所以请注意,这与它的存储位置无关,它更像是在服务器端查找它的位置。