2. JWT 签名算法:HS256、RS256、ES256 原理与区别
JWT 的安全性高度依赖签名算法。选择错误的算法可能导致令牌被伪造、密钥泄露或性能瓶颈。本节从密码学原理、性能特征和适用场景三个维度,深入对比三种主流签名算法。
2.1 算法分类与核心原理
JWT 签名算法分为对称签名和非对称签名两大类。HS256 属于对称算法,RS256 和 ES256 属于非对称算法。它们的核心区别在于密钥管理方式和计算复杂度。
关键概念:对称签名使用同一个密钥进行签名和验签;非对称签名使用私钥签名、公钥验签,私钥必须保密,公钥可以公开分发。
2.2 三种算法详细对比
| 对比维度 | HS256 | RS256 | ES256 |
|---|---|---|---|
| 算法类型 | 对称 (HMAC-SHA256) | 非对称 (RSA-SHA256) | 非对称 (ECDSA-SHA256) |
| 密钥长度 | 任意长度(建议 ≥ 32 字节) | 2048~4096 位 | 256 位(P-256 曲线) |
| 签名速度 | 极快 | 较慢 | 快 |
| 验签速度 | 极快 | 较快 | 快 |
| 签名长度 | 32 字节 | 256 字节 | 64~72 字节 |
| 密钥分发 | 需安全通道共享密钥 | 公钥可公开,私钥保密 | 公钥可公开,私钥保密 |
| 多服务验签 | 所有服务需持有相同密钥 | 仅需分发公钥 | 仅需分发公钥 |
| 密钥轮换 | 困难(所有服务同步更新) | 容易(公钥不变,换私钥) | 容易(公钥不变,换私钥) |
2.3 算法原理详解
2.3.1 HS256 (HMAC-SHA256)
HS256 使用 HMAC 结构,将密钥与消息进行两次哈希运算。签名过程:signature = HMAC-SHA256(secret, header + "." + payload)。验签时接收方使用相同的密钥重新计算 HMAC,比对结果是否一致。
安全风险:HS256 要求签名方和验签方共享同一个密钥。如果密钥泄露,攻击者可以伪造任意 JWT。在微服务架构中,每个服务都必须持有密钥,增大了泄露面。此外,HS256 无法实现非否认性——无法证明令牌是由特定签发者生成的。
2.3.2 RS256 (RSA-SHA256)
RS256 使用 RSA 公钥密码体系。签发者使用私钥对 JWT 的 header 和 payload 进行 RSA 签名,验签者使用对应的公钥验证签名。RSA 签名基于大整数分解难题,2048 位密钥提供约 112 位安全强度。
签名过程:
- 对
header.payload进行 SHA-256 哈希,得到消息摘要 - 使用私钥对摘要进行 RSA 加密(PKCS#1 v1.5 或 PSS 填充)
- 将加密结果作为签名附加到 JWT 末尾
2.3.3 ES256 (ECDSA-SHA256)
ES256 使用椭圆曲线数字签名算法,基于 NIST P-256 曲线(secp256r1)。ECDSA 在相同安全强度下,密钥长度远小于 RSA。256 位 ECDSA 密钥提供约 128 位安全强度,与 3072 位 RSA 相当。
签名过程:
- 对
header.payload进行 SHA-256 哈希 - 使用私钥和随机数 k 生成签名对 (r, s)
- 将 (r, s) 编码为 DER 格式或原始字节序列
性能提示:ES256 的签名速度比 RS256 快 5~10 倍,验签速度快 3~5 倍。在压测场景下,ES256 的 CPU 开销显著低于 RS256,适合高并发令牌签发场景。
2.4 签名算法选择建议
选择签名算法需要综合考虑安全需求、架构规模和性能要求。以下决策矩阵可以帮助你做出选择:
| 场景 | 推荐算法 | 理由 |
|---|---|---|
| 单体应用,内部服务调用 | HS256 | 实现简单,性能最优,密钥管理成本低 |
| 微服务架构,多服务验签 | RS256 或 ES256 | 公钥分发方便,无需共享密钥,支持独立密钥轮换 |
| 第三方开放 API,多客户端 | RS256 或 ES256 | 客户端仅需公钥即可验签,保障签发者私钥安全 |
| 高并发令牌签发(>10K TPS) | ES256 | 签名速度快,密钥短,网络传输开销小 |
| 遗留系统兼容,已有 RSA 基础设施 | RS256 | 与现有 PKI 体系集成方便,工具链成熟 |
| IoT 设备,计算资源受限 | ES256 | 密钥短,计算量小,适合低功耗设备 |
2.5 算法选择避坑指南
- 不要在生产环境使用 "none" 算法:某些 JWT 库允许将算法设置为 "none",这会导致令牌不被签名。务必在服务端校验算法白名单。
- 不要混淆对称与非对称:如果使用 RS256 签发,但验签时误用 HS256 逻辑,攻击者可能通过获取公钥来伪造令牌(算法混淆攻击)。
- HS256 密钥长度不要过短:建议使用至少 32 字节(256 位)的随机密钥。过短的密钥容易被暴力破解。
- RS256 密钥不要小于 2048 位:1024 位 RSA 密钥已被认为不安全,建议使用 2048 位或更高。
- ES256 必须使用安全的随机数生成器:ECDSA 签名依赖高质量的随机数 k。如果 k 可预测或重复使用,私钥可能被恢复。
压测视角建议:在压测环境中,建议使用 ES256 进行签名性能测试。相比 RS256,ES256 在相同安全强度下 CPU 消耗降低约 60%,可以更准确地反映业务逻辑本身的性能瓶颈,而非签名计算的开销。