JWT 签名用对称加密还是非对称加密?

一 概念梳理

对称加密和非对称加密是两种基本的加密方法,它们在现代密码学中扮演着核心角色,用于保护数据的安全和隐私。

1.1 对称加密(Symmetric Encryption)

对称加密是指加密和解密使用同一个密钥的过程。这意味着发送方和接收方都必须知道并使用这个共享的密钥来对信息进行加密和解密。这种方法的优点在于加密和解密速度快,效率高,适合处理大量数据。但是,安全分发密钥成为一个挑战,因为如果密钥在传输过程中被截获,那么加密的信息就可能被破解。常用的对称加密算法有 DES(Data Encryption Standard)、3DES(Triple DES)、AES(Advanced Encryption Standard)等。

1.2 非对称加密(Asymmetric Encryption)

非对称加密则使用一对密钥,分别是公钥(Public Key)和私钥(Private Key)。公钥可以公开给任何人,用于加密信息;而私钥必须保密,仅由信息的接收者持有,用于解密信息。这种机制解决了密钥分发的问题,因为即使公钥被广泛传播,只要私钥保持安全,信息仍然是安全的。非对称加密的计算复杂度较高,速度相对较慢,因此通常用于加密小量的数据,或者用来安全地交换对称加密的密钥。常见的非对称加密算法有 RSA、DSA(Digital Signature Algorithm)、ECC(Elliptic Curve Cryptography)等。

对称加密适用于数据的快速加密和解密,但需要安全的密钥管理机制;而非对称加密提供了更好的安全性,尤其在密钥交换方面,尽管其加密和解密过程比对称加密更耗时。在实际应用中,这两种加密方式常常结合使用,例如在 HTTPS 的处理中。

二 JWT

2.1 JWT 简介

JSON Web Token(JWT)是一种轻量级、自包含的安全标准,用于在各方之间安全地传输信息。它以 JSON 对象的形式存在,包含三个部分:Header(头部)、Payload(载荷)和Signature(签名)。JWT 被广泛应用于认证、授权和信息交换场景,如单点登录(SSO)、API 安全认证等。

JWT 的优势在于:

  • 无状态性:服务器无需存储会话信息,降低了服务器负担。
  • 自包含:所有必要信息直接包含在 JWT 中,便于跨域传输。
  • 安全性:通过签名机制确保数据的完整性和防篡改。

2.2 JWT 如何防篡改

JWT 通过其内置的签名机制来防止数据被篡改,确保消息的完整性和真实性。JWT 的结构分为三部分:Header、Payload 和 Signature。签名部分正是 JWT 防止篡改的关键所在,其生成和验证流程如下:

签名生成过程

  1. Header 和 Payload 编码:首先,JWT 的 Header 和 Payload 分别被 Base64Url 编码,形成两段字符串。Header 包含了关于 JWT 的元数据,如签名算法类型;Payload 则包含了实际要传输的数据,如用户标识、过期时间等。

  2. 签名数据准备:将编码后的 Header 和 Payload 通过 . 连接起来形成一个字符串,这个字符串与用于签名的密钥(可以是对称密钥或私钥,依据所选签名算法而定)一起作为签名的输入。

  3. 签名计算:根据 Header 中声明的签名算法(如 HMAC SHA256、RSA、ECDSA 等),使用密钥对上述拼接的字符串进行加密计算,产生一个签名字符串。

  4. 组合 JWT:最后,将 Base64Url 编码的 Header、Payload 和新产生的 Signature 通过 . 连接,形成完整的 JWT 字符串。

防篡改验证过程

  1. 接收 JWT:接收方首先解析 JWT,将其分割成 Header、Payload 和 Signature 三部分。

  2. 签名验证:再次对 Header 和 Payload 进行 Base64Url 解码,并使用声明的签名算法和相应的密钥(如果是对称加密,则与签名时使用的密钥相同;如果是非对称加密,则使用与私钥配对的公钥)对这两部分数据进行计算,生成一个新的签名字符串。

  3. 比较签名:将新生成的签名与 JWT 中携带的原始 Signature 进行对比。如果两者完全一致,则说明在传输过程中 JWT 没有被篡改,其内容是完整且真实的;若不一致,则表明 JWT 可能被篡改或不是由预期的发送方发出。

三 选择那种签名方案

根据上面的介绍,在签名的时候存在两类不同的签名方式:对称加密和非对称加密。

选择使用共享密钥(HMAC)还是公私钥对(如RSA、ECDSA)来签名 JWT 取决于具体的应用场景和安全需求。

3.1 共享密钥(HMAC)

优点

  • 实现简单:相较于公私钥对,使用共享密钥进行签名和验证的实现更为直接和快速。
  • 计算效率高:HMAC 算法的计算速度通常比 RSA 等非对称加密算法快,适合对性能有较高要求的场景。
  • 密钥管理相对简单:只需保护好一个密钥即可,减少了密钥管理的复杂度。

缺点

  • 密钥分发风险:所有需要验证 JWT 的服务都需要访问这个共享密钥,增加了密钥泄露的风险。
  • 不支持非对称操作:无法实现 JWT 的签发者和服务验证者之间的分离,因为双方都需要知道相同的密钥。

3.2 公私钥对

优点

  • 增强安全性:私钥保持在签发者一方,公钥可以公开,即使 JWT 在传输过程中被截取,没有私钥也无法伪造 JWT,提高了安全性。
  • 分离权限:可以实现签发和验证的职责分离,例如,认证服务器使用私钥签发 JWT,而各个服务使用公钥验证,无需共享私密信息。
  • 更灵活的架构设计:适用于分布式系统,特别是当有多个服务需要验证 JWT,但不应知道用于签名的私钥时。

缺点

  • 实现复杂度:公私钥的管理和使用相比 HMAC 更复杂,尤其是在密钥的生成、存储和更新方面。
  • 性能开销:非对称加密算法的计算成本高于对称加密,可能影响到大规模系统中的性能。

四 小结

如果你的应用场景对性能要求较高,且信任环境较为封闭,可以考虑使用共享密钥。

若你需要更高的安全性,或者在分布式系统中需要明确分离 JWT 的签发和验证权限,公私钥对会是更好的选择,尽管它在实现和性能上可能带来一些挑战。

如果小伙伴们想要彻底掌握 Spring Security+OAuth2,那么可以看看松哥最近录制的这套全新的视频教程:

基本上把 Spring Security 的方方面面以及 OAuth2 都讲到了。最重要的是,贴合了很多小伙伴们日常常见的开发场景,比如短信验证码登录、JWT+Redis 登录、微信 OAuth2 登录等等都有讲到。

这套视频是基于目前最新版的 Spring Security6 录制的,Spring Security6 在 API 层面的变化还是蛮大的,引入了大量的 Lambda 表达式去简化配置,很多旧版的写法在 Spring Security6 中被废弃,并在将来在 Spring Security7 中会移除相关的 API,所以说最近的 Spring Security 更新还是蛮激进的。

另一方面就是这套视频包含了全新的基于目前最新版 Spring Security 录制的 OAuth2 教程,松哥在 2020 年的时候出过图文版的 OAuth2 教程,但是,现在新版的 OAuth2 也有很多变化,不仅仅是 API 层面的变化,授权模式也发生了一些变化,传统的密码模式、简化模式现在都不再推荐,转而引入了 PKCE 模式,并且利用 OIDC 简化用户信息获取。同时,在 2020 年还处于萌芽状态的 Spring Security OAuth2 Server 这个项目,目前也趋于成熟,也可以直接使用了,这些松哥都在视频中和大家做了详细介绍。在 OAuth2 环节我也和大家分享了如何使用微信的 OAuth2 登录。

总之这一套教程,让大家彻底理解系统的安全管理。

之前有小伙伴说我直接自己写过滤器,既灵活还简单。我并不反对这种做法,但是有一个前提就是你很牛,你自己写的过滤器有考虑到计时攻击,有考虑到 XSS 攻击,有考虑到点击劫持,有考虑跨站请求伪造。。。等等太多了。当然,这些问题如果你都没有考虑到,那么 Spring Security 都有帮你考虑到并提供解决方案!

理解了 Spring Security,再去看市面上其他的安全管理框架,都会豁然开朗。

不同于松哥之前其他教程的交付方式,这套教程使用微信群答疑并且不再使用一机一码绑定设备播放,小伙伴们可以在任意设备上登录自己的账号就可以学习了,很便捷。

下面是两个试看视频:

这套视频是付费的,¥499,有需要的小伙伴加微信备注 499

松哥在 2021 年出版了《深入浅出 Spring Security》(清华大学出版社,2021),所以这套视频教程绝对够专业。