JWT 令牌安全指南:最佳实践详解

JSON Web Tokens (JWT) 已成为无状态身份验证的行业标准。它们允许服务器在不存储会话数据的情况下验证用户身份。然而,这种无状态特性如果实现不当,会引入特定的安全风险。在本指南中,我们将探讨如何正确保护 JWT 令牌,以保护用户数据并维护应用程序的完整性。

理解 JWT 结构

在深入安全措施之前,了解 JWT 的三个部分至关重要:头部、载荷和签名。

  1. 头部: 包含用于签署令牌的算法(例如 HS256、RS256)。
  2. 载荷: 包含声明(关于用户的数据,如 ID 和角色)。
  3. 签名: 确保令牌未被篡改。

由于载荷是 base64 编码的,任何拦截令牌的人都可以读取它。这就是为什么 HTTPS 和签名验证等安全措施是不可商量的。

1. 始终使用 HTTPS

保障任何令牌安全的最基本步骤是确保通过安全通道传输。如果 JWT 通过 HTTP 发送,网络上的攻击者可以拦截并读取令牌载荷,从而提取敏感的用户信息。

BBVA 强调,使用 HTTPS 是防止中间人攻击的强制要求。这种加密确保了令牌从离开客户端到到达服务器的整个过程中保持机密性。

2. 保护您的签名密钥

签名是 JWT 中唯一证明令牌真实性的部分。要生成有效的签名,您需要一个密钥(用于对称算法)或私钥(用于非对称算法)。

不要硬编码密钥

开发人员最常见的错误之一是将密钥直接硬编码到源代码中。如果代码被推送到公共仓库(如 GitHub),密钥就会被暴露。H2S Media 建议不要这样做,而是推荐使用环境变量来存储密钥。这可以将敏感数据与应用程序逻辑分开,防止意外泄露。

定期轮换密钥

即使您的密钥存储安全,也应定期轮换。如果密钥泄露,攻击者可以无限期地伪造令牌。定期轮换限制了攻击者的作案窗口。

3. 选择正确的存储机制

在客户端存储 JWT 是一个关键的安全决策。主要选项是 LocalStorage 和 HttpOnly Cookie。

LocalStorage 的风险

将 JWT 存储在 localStorage 中会使页面上的任何 JavaScript 都可以访问它们。如果您的应用程序存在跨站脚本(XSS)漏洞,攻击者可以轻松窃取令牌并冒充用户。MakeUseOf 指出,虽然 localStorage 很方便,但它容易受到 XSS 攻击。

HttpOnly Cookie 的安全性

HttpOnly Cookie 无法通过 JavaScript 访问。这使得它们对尝试窃取令牌的 XSS 攻击免疫。为了最大程度的安全,特别是在处理敏感数据的应用程序中,将 JWT 存储在 HttpOnly Cookie 中是推荐的方法。如果结合适当的 SameSite 属性,这种方法还有助于缓解 CSRF(跨站请求伪造)攻击。

4. 实施短过期时间

JWT 旨在保持无状态,这意味着它们在过期前一直有效。然而,令牌有效期越长,被拦截的风险就越高。AWS 建议对访问令牌使用短过期时间。通过保持 TTL(生存时间)较短,您可以限制攻击者在成功窃取令牌后能造成的损害。

刷新令牌模式

为了在不增加安全风险的情况下保持无缝的用户体验,开发人员通常结合使用短期访问令牌和长期刷新令牌。访问令牌授予对 API 的即时访问权限,而刷新令牌用于获取新的访问令牌。刷新令牌应安全存储,通常存储在 HttpOnly Cookie 中,并具有较长的过期时间。

5. 处理令牌撤销

JWT 的固有挑战之一是它们是无状态的。一旦签发,有效的令牌在过期前仍然有效,即使用户注销或更改密码也是如此。这使得撤销变得困难。

短 TTL 作为撤销策略

如前所述,处理撤销最有效的方法是保持非常短的过期时间。如果令牌泄露,攻击者只能有限的时间使用它。

黑名单

对于需要立即撤销的应用程序,可以实现有状态的黑名单。当用户注销或会话无效时,您可以将令牌的 ID(JTI)添加到数据库或缓存中。在验证令牌之前,服务器会检查 JTI 是否在黑名单中。然而,这种方法需要维护状态,这与 JWT 的无状态特性相矛盾。

6. 验证令牌声明

接收 JWT 时,您的服务器必须进行严格的验证。AWS 详细说明了验证发行者、受众和过期声明的重要性。

如果不验证这些声明,可能会导致授权绕过,即用户获得他们不应拥有的资源访问权限。

7. 考虑 PASETO 等替代方案

虽然 JWT 广泛使用,但它们有安全漏洞的历史。例如,“none”算法漏洞允许攻击者伪造令牌。HackerNoon 讨论了 PASETO(令牌认证、安全和加密平台)的兴起,这是一种旨在解决 JWT 漏洞的新令牌标准。PASETO 支持对称和非对称密钥,并旨在通过默认更安全。虽然 JWT 仍然是标准,但对于做出长期决策的架构师来说,了解 PASETO 等替代方案至关重要。

常见问题

HS256 和 RS256 有什么区别?

HS256(HMAC with SHA-256)在客户端和服务器之间使用共享密钥。RS256(RSA with SHA-256)使用私钥签署令牌,使用公钥验证它。RS256 通常被认为对分布式系统更安全,因为私钥永远不会离开服务器。

我可以立即撤销 JWT 吗?

由于 JWT 是无状态的,如果不维护黑名单或使用短过期时间,您无法技术上立即撤销 JWT。最实用的解决方案是使用短期访问令牌。

LocalStorage 对 JWT 安全吗?

不,LocalStorage 容易受到 XSS 攻击。如果您的应用程序受到损害,攻击者可以读取 LocalStorage 并窃取 JWT。HttpOnly Cookie 是推荐的存储机制。

结论

保护 JWT 需要多层方法。通过使用 HTTPS、安全地管理密钥、将令牌存储在 HttpOnly Cookie 中、实施短过期时间并严格验证声明,您可以显著降低令牌被盗和滥用的风险。随着 Web 安全格局的发展,了解最佳实践和 PASETO 等替代方案对于维护强大的安全态势至关重要。

参考资料

  1. JWT vs PASETO: What's the Best Tool for Generating Secure Tokens?
  2. How to Build a Secure Nest.js REST API Using JWT and MongoDB
  3. How to secure API Gateway HTTP endpoints with JWT authorizer
  4. Best of 2021 – How to Revoke JSON Web Tokens (JWTs)
  5. JSON Web tokens (JWT): how to use them safely
  6. How to Create a JWT Secret in Node.js (Best Practices + Examples)
  7. How to monitor, optimize, and secure Amazon Cognito machine-to-machine authorization