JWT 与 Paseto - 基于令牌的身份验证的新时代(翻译)
对 JWT vs PASETO: New Era of Token-Based Authentication 一文的中文翻译。原文对 Paseto 和 JWT 进行全面比较,并剖析了它们的核心功能、安全特性和潜在缺点。我在翻译过程中参考了其他资料并添加了一些译注,以帮助您更好地理解原文。
API 和现代 Web 应用使基于令牌(Token)的身份验证成为最重要的安全授权方法。与传统的基于会话的(Session-based)身份验证相比,令牌具有可扩展性(scalability)、无状态性(statelessness)和更高安全性等优势,已成为全球开发人员的首选。
在各种基于令牌的方法中,JSON Web Token (JWT) 因其简单易用而广受欢迎。然而,由于对潜在漏洞的担忧,以及必须仔细使用 JWT 以防出现问题的需要,人们开始探索更稳健的替代方案。
Paseto (Platform-Agnostic Security Tokens,平台不可知安全令牌) 是一种更好的解决方案,直接解决了 JWT 的缺陷。Paseto 以安全为设计重点,通过减少漏洞和执行安全默认设置,为基于令牌的身份验证提供了更安全的基础。
本文全面比较了 Paseto 和 JWT,剖析了它们的核心功能、安全特性和潜在缺点。通过分析它们各自的优缺点,旨在让您掌握相关知识,以便在项目中就基于令牌的身份验证做出明智的选择。
基于令牌的身份验证是如何工作的?
基于令牌的身份验证为管理现代应用中的用户访问提供了一种安全高效的方法。与依赖服务器端存储的基于会话的传统方法不同,基于令牌的系统会在认证成功后向客户端发送令牌。
让我们来分析一下典型的流程:
- 用户登录:用户通过向服务端提供凭据(Credentials,即用户名和密码)来开始整个身份验证流程。
- 身份验证:服务端根据数据库或其他认证机制验证这些凭证,从而核实用户的身份。
- 令牌生成:验证成功后,服务端会生成一个包含相关用户信息和权限的唯一数字签名令牌。该令牌是用户身份和访问权限的安全凭证。
- 令牌传输:服务端将生成的令牌发送给客户端,通常包含在 HTTP 响应头或响应体中。
- 客户端存储:客户端需要安全地存储收到的令牌,通常存储在本地存储(Local Storage)、会话存储(Session Storage)或 Cookie 中,以便在后续请求中使用。
- 资源请求:客户端需要访问受保护的资源时,会在 HTTP 请求的授权(
Authorization
)标头中包含令牌。这就向服务端发出了信号,表明客户端正试图访问受限的区域或内容。 - 令牌验证:当收到带有令牌的请求时,服务端通过使用令牌签名算法的相应密钥或公钥来确认其有效性和完整性。
- 访问控制:服务端根据经过验证的令牌及其内嵌权限,确定客户端是否拥有访问所请求资源的必要授权。如果获得授权,服务端将允许访问并满足请求。否则,拒绝访问。
上述流程图示如下:
什么是 JWT
JWT 是 JSON Web Token 的缩写。它是一个开放标准(RFC 7519),定义了一种紧凑、自包含(Self-contained)的方法,用于在各方之间以 JSON 对象的形式安全地传输信息。
JWT 通常用于验证用户身份和授权访问私人资源。此外,通过 JWT,您还可以在应用程序之间安全地共享信息。
一个 JWT 包含三个部分:
令牌头(Header):定义令牌类型(JWT)和使用的签名算法。例如:
{
"alg": "HS256",
"typ": "JWT"
}
载荷:它包含有关实体(通常是用户)的声明和附加数据。例如:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
签名:这一部分确保了验证令牌的真实性和完整性。它是由经过编码的令牌头、经过编码的载荷、密钥和指定的签名算法组合而成的。例如(使用 HMAC SHA256):
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Tip
译注:在 JWT 的设计中,开发人员可以根据不同的用途,自行选择所采用的签名算法。
在对称数字签名算法中,签名(Sign)和验证(Verify)使用的是同一个密钥。这样的签名算法对应于本地用途,例如在内部服务中,我们可以直接共享这些密钥。这些算法包括 HS256、HS384、HS512:
- HS256 = HMAC + SHA256
- HMAC: Hash-based Message Authentication Code
- SHA: Secure Hash Algorithm
- 256/384/512: 表示输出的位数
在非对称数字签名算法中,私钥被用于签名,公钥被用于验证。这样的签名算法应用于公共用途,内部服务进行签名,外部服务进行验证。这些算法包括:
- RS256, RS384, RS512 || PS256, PS384, PS512 || ES256, ES384, ES512
- RS256 = RSA PKCSv1.5 + SHA256 [PKCS: Public-Key Cryptography Standards]
- PS256 = RSA PSS + SHA256 [PSS: Probabilistic Signature Scheme]
- ES256 = ECDSA + SHA256 [ECDSA: Elliptic Curve Digital Signature Algorithm]
对称数字签名算法适用于性能要求更高、信任模型简单、仅在内部受控的系统中使用的业务场景,非对称数字签名则适用于安全性要求更高、信任模型复杂、需要与外部系统协作使用的业务场景中。
JWT 是如何工作的?
JWT 的工作流程包括:
- 令牌生成:用户身份验证成功后,服务端会生成一个包含用户信息和权限的 JWT,并使用密钥对其签名。
- 向客户端发送令牌:服务端将 JWT 发送给客户端,通常是在 HTTP 响应头中。
- 客户端存储令牌:客户端安全地存储 JWT,通常存储在本地存储(Local Storage)或 Cookie 中。
- 客户端请求资源:客户端将 JWT 包含在对私有资源的后续请求的授权(
Authorization
)标头中。 - 服务端验证令牌:服务端使用密钥验证 JWT 的签名和过期时间。
- 允许/拒绝访问:服务端根据令牌验证结果,允许或拒绝访问请求的资源。
JWT 的缺陷
虽然 JWT 有很多优点,但您必须意识到,如果使用不当,可能会产生的潜在隐患和安全问题。
以下是与 JWT 相关的一些关键问题:
- 算法选择不当带来的安全风险:JWT 有不同的加密方法。如果加密方法选择不当或使用不当,就很容易受到攻击。
- 密钥管理问题:如果用于创建和验证 JWT 的密钥被泄露,攻击者就可能伪造令牌并进行未经授权的访问。
- 难以撤销:JWT 一旦发布,就难以撤销。这意味着,如果用户的令牌被泄露,它们可能仍然有效,但我们却难以阻止那些使用已泄露令牌的访问。
- 绕过签名验证:某些 JWT 库和实现中的漏洞允许绕过签名验证。这些漏洞可使攻击者创建在应用程序看来合法的伪造令牌。
Tip
译注:JWT 给开发人员提供了过大的自行选择所使用的签名算法的自由,这成为了它的一个缺陷。因为开发人员可能并不清楚哪些签名算法更为安全、哪些已经证实了存在漏洞(例如 RSA PKCSV1.5 易受密文填塞攻击,ECDSA 易受无效曲线攻击(Invalid-Curve Attack))。
攻击者可以通过算法混淆攻击,通过将 JWT 头部的 alg
设置为 none
、将一个非对称签名算法替换为一个对称签名算法等方式实施攻击。
什么是 Paseto(平台不可知安全令牌)?
Paseto (Platform-Agnostic Security Tokens) 是一种安全无状态令牌规范。
它是 JWT 的一个现代化的、更好的替代方案,解决了 JWT 的一些固有漏洞,并强调了安全默认值和使用的简易性。
Paseto 的结构
与 JWT 的单一通用结构不同,Paseto 基于不同的令牌用途采用了版本化方法:
- 本地令牌:这是为有状态的服务端会话设计的,令牌安全地存储在服务端,并与用户的会话相关联。
- 公共令牌:适用于涉及公钥加密的无状态应用和用例。这些令牌可以安全地传输和验证,无需服务器端存储。
本地令牌和公共令牌的结构相似,都由三部分构成:
- 令牌头:该部分标识 Paseto 版本和用途(本地或公共),以及所使用的特定加密算法。
- 载荷:与 JWT 类似,载荷包含代表实体(通常是用户)信息的声明(Claims)以及与应用程序相关的任何附加数据。
- 令牌尾(可选):这一部分可以包含额外的验证数据,为令牌提供额外的安全性和上下文。
Tip
译注:在 Paseto 中,开发人员无须指定具体的算法,只需要指定版本。最多只有两个版本是激活版本,目前(2024 年 12 月 2 日)最新的是 v3 和 v4,具体请见 Paseto 官网。
Paseto 是如何工作的?
Paseto 的核心优势在于其专注于安全默认设置和定义明确的使用。
通过明确指定每个版本和目的应使用的加密算法,消除了 JWT 中已知的漏洞 —— 算法混乱的风险。这种方法可确保开发人员不会无意中选择不安全的选项。
- 本地令牌:通常使用对称加密算法,加密和解密都使用相同的密钥。这使它们适合服务端会话管理,由服务器保持对密钥的控制。
- 公共令牌:采用公钥加密技术,包括用于加密的公钥和用于解密的私钥。这样就能在不共享密钥的情况下实现安全通信和验证。
Tip
译注:以 Paseto 为例:
- 本地令牌模式(对称加密)
- 载荷 Payload:加密后经过 Base64 编码
- 令牌尾 Footer:仅 Base64 编码,不加密
- 公共令牌模式(非对称加密)
- 载荷 Payload:签名后经过 Base64 编码,不加密(这意味着可以从中读取,但不能篡改)
- 令牌尾 Footer:仅 Base64 编码,不加密
如何在您的项目中使用 JWT 或者 Paseto?
以下是在项目中使用 JWT 或 Paseto 的基本指南:
- 选择库:为项目选择一个库。对于流行的语言,如 Python、Node.js、Java 和 Ruby,您都有很多选择。
- 生成密钥:创建一个强密钥,用于签署和验证令牌。将它安全地存储起来。对于本地令牌,只需要一个安全密钥。对于公共令牌,需要生成公私密钥对。
- 实现令牌生成:开发一种机制,在用户身份验证成功后生成令牌,并在载荷中包含相关声明(Claims)。
- 实现令牌验证:在服务器端实现逻辑来验证请求中收到的令牌,验证签名和过期时间。
- 安全存储令牌:在客户端安全存储 JWT(例如,带有安全标记的 HttpOnly cookies)。
- 处理令牌过期:实现处理过期令牌的策略,例如刷新令牌或要求重新验证。
- 提取和验证载荷:此步骤仅适用于 Paseto。在 Paseto 中,验证载荷将确保信息的真实性和完整性。
JWT vs Paseto
结构
方面 | Paseto | JWT |
---|---|---|
方法 | 基于不同用途(本地或公共)的版本化的方法 | 单一且泛用的结构 |
组件 | 令牌头、载荷、可选的令牌尾 | 令牌头、载荷、签名 |
格式规则 | 更严格的格式和使用规则 | 更加灵活,可采用各种算法和声明(Claims) |
安全特性
方面 | Paseto | JWT |
---|---|---|
算法是否混乱 | 按版本/用途指定算法,从而消除了这一问题 | 存在允许使用 “none” 算法的潜在漏洞 |
密钥管理 | 从设计上推进更好地实践 | 需要谨慎使用以避免漏洞 |
撤销 | 由于采用了版本管理和特定用途设计,因此更加简便 | 无状态特性使其具有挑战性;需要额外的机制 |
配置默认值 | 强制执行安全算法和配置 | 如果使用不慎,可能会出现配置错误和漏洞 |
用例场景
令牌类型 | Paseto | JWT |
---|---|---|
本地令牌 | 有状态服务器端会话(如传统网络应用程序) | 可用于各种用例,包括有状态和无状态应用程序 |
公共令牌 | 使用公钥加密技术进行无状态认证 | 适用于各种情况,但需要仔细考虑安全影响 |
了解如何撤销令牌是构建安全系统的重要议题之一,我们将在下一节深入了解这个问题。
深入了解令牌的撤销
令牌撤销是安全身份验证的重要组成部分。它能确保不安全的令牌失效,防止未经授权的访问。下面将详细介绍分别应该如何在 JWT 和 Paseto 上实现令牌的撤销。
JWT:
- 由于 JWT 通常是无状态的,除非使用特定的撤销机制,否则服务端不会跟踪已发出的令牌。
- 撤销 JWT 的常用办法:
- 黑名单:维护一份已撤销令牌的列表,服务端在允许访问前会检查该列表。
- 令牌绑定:这种方法将令牌与特定的 User Agent 联系起来,如果它发生变化,令牌就会失效。
- 专用撤销服务:一个单独的服务,可以管理令牌撤销并与服务端通信。
Paseto:
- 本地令牌:如前所述,服务端会维护一份已签发的本地令牌列表,从而使撤销令牌变得更简单。当用户注销时,服务器会使令牌失效,从而阻止进一步访问。
- 公共令牌:这些令牌是无状态的,因此服务器没有活动令牌列表。您需要使用上面提到的那些或其他解决方案来处理撤销问题。
令牌撤销的最佳实践
- 使用更好的撤销机制:选择一种符合应用程序安全要求和令牌类型的方法。
- 确保通信正常:如果您使用专门的撤销服务,请确保该服务与您的应用程序安全集成。
- 测试撤销过程:定期测试您的撤销系统,以确认其按预期运行。
除了令牌撤销,还有其他一些架构模式可以提高令牌的安全性和管理。BFF (Backend For Frontend) 就是这样一种模式。
BFF 模式
Backend for Frontend(BFF)模式是一种处理身份验证和令牌管理的强大方法。它通常与 Oauth 一起使用。BFF 包括一个服务器端前端(如 Next.js),作为客户端和后端的桥梁。
BFF 在服务器端管理令牌,只向客户端发送 cookie。这样就无需客户端存储令牌,从而提高了安全性。
BFF 模式的好处
- 增强安全性:在服务器端保留令牌可降低客户端漏洞和令牌被盗的风险。
- 简化客户端开发:客户端只需管理 cookies,使开发更轻松。
- 提高性能:BFF 可为客户端优化 API 请求。
您可以通过评估 BFF 模式是否符合您的架构和安全要求以确定是否使用 BFF 模式。
选择 Paseto 还是 JWT
Paseto 和 JWT 都有明显的优势和劣势,因此如何选择取决于您的具体需求和优先事项。
以下是一些可能影响您做出决定的因素:
安全需求
- Paseto:如果您的应用程序需要强大的安全性和对常见漏洞的保护,那么 Paseto 可能最适合您。因为它旨在缓解算法混乱等问题,促进更好的密钥管理实践,确保更高水平的安全性。
- JWT:虽然 JWT 在正确使用的情况下是安全的,但它需要对细节一丝不苟的关注和对潜在隐患的透彻了解。开发人员必须提高警惕,避免常见的错误配置和漏洞。
应用架构
- Paseto:Paseto 对本地令牌和公共令牌进行了明确区分,以满足不同的架构要求。本地令牌专为有状态的服务器端会话而设计,是具有会话管理功能的传统网络应用程序的理想选择。公共令牌面向无状态应用程序和公钥加密,非常适合微服务和 API 驱动型架构。
- JWT:它的结构灵活,既适用于有状态应用程序,也适用于无状态应用程序。不过,如果处理不慎,这种灵活性也可能导致模糊不清和潜在误用。
开发人员熟悉程度
- Paseto:虽然 Paseto 的生态系统正在稳步发展,但其支持的广度和深度可能还无法与 JWT 相提并论。开发人员可能需要投入更多精力来寻找合适的库并了解 Paseto 的具体实现。
- JWT:由于 JWT 较早被采用并得到广泛使用,它受益于一个更大的社区以及各种编程语言中随时可用的库、框架和文档。这使得开发人员更容易找到资源并在其项目中使用 JWT。
生态支持
- Paseto:它的生态系统正在扩大,在流行的编程语言中有着越来越多的库和工具。不过,它可能还无法与 JWT 的全面支持相媲美,尤其是对不太常用的语言或框架。
- JWT:JWT 在众多编程语言、框架和库中享有广泛支持。这种广泛采用确保了资源的随时可用性,并简化了与现有工具和基础设施的集成。
Web 令牌的未来
加密技术的进步、不断变化的安全威胁以及对安全高效身份验证机制与日俱增的需求,推动着网络令牌的不断发展。以下是一些可能塑造网络令牌未来的新想法:
更强的安全性和密码学
- 抗量子加密:随着量子计算机打破现有加密算法的可能性日益增加,开发和采用抗量子算法对网络令牌的未来发展至关重要。
- 后量子加密技术:一些研究和标准化工作正在开发后量子加密算法,并希望将其集成到基于令牌的系统中,确保长期安全性和抵御量子威胁的能力。
去中心化身份和 SSI
- 可验证凭证:随着可验证凭证的兴起,个人可以控制和管理自己的数字身份,这可能会影响到如何使用令牌进行身份验证和授权。
- 去中心化标识符(Decentralized Identifier,DID):这项技术为去中心化和自拥有 ID 的实现提供了可能,并可与基于令牌的系统集成,以加强隐私和用户对个人数据的控制。
更高的可用性和标准化程度
- 简化令牌管理:努力简化令牌生成、撤销和更新流程将改善用户体验,提高开发人员的效率。
- 令牌格式和协议的标准化:令牌格式和通信协议的进一步标准化将促进互操作性,简化不同平台和服务之间的集成。
新出现的令牌机制
- Macaroons:这提供了一种更灵活、更细粒度的授权方法,允许访问权限的分派和按需减弱。
- 令牌绑定:这种机制可以减少令牌失窃和重放攻击,提高基于令牌的系统的安全性。
对 Paseto 和 JWT 的影响
Paseto 专注于安全性和定义明确的用例,这使它非常适合在具有高安全性要求和重视标准化的环境中使用。它的版本化方法允许适应和整合未来的加密进步。
JWT 的灵活性和广泛采用可能会使它继续在各种应用中使用。不过,由于其安全缺陷,可能需要额外的保障措施和谨慎的实施方法来降低风险。
网络令牌的未来可能会涉及现有机制和新兴机制的结合,每种机制都要满足特定的需求和安全考虑。
总结
在本文中,我们重点介绍了每种令牌机制的优缺点,强调了了解您的具体需求和优先事项的重要性。
JWT 提供了简单性和灵活性,而 Paseto 则优先考虑安全性和定义明确的用例。
评估安全需求、应用架构和开发人员熟悉程度等因素将引导您选择最合适的方案。
此外,探索像 Permify 这样的新兴解决方案(它提供了一个具有细粒度访问控制的综合授权平台),可以进一步增强您应用程序的安全性和灵活性。
在 JWT 和 Paseto 之间做出选择并不是一个放之四海而皆准的答案,而是要根据您的独特情况做出决定。
让我们继续对话!加入原作者的 Discord 社区,分享您对 JWT、Paseto 和其他令牌机制的看法和经验。
参考
JWT 资源:
Paseto 资源:
进一步阅读: