JWT 的签名算法是保证其安全性的关键,以下是主要签名算法的对比和选择建议:
主要签名算法
1. HS256 (HMAC SHA256)
对称加密算法,使用相同的密钥进行签名和验证。
特点:
- 性能较好,计算速度快
- 密钥管理复杂,需要安全地共享密钥
- 适合单服务应用
示例:
javascriptconst token = jwt.sign(payload, 'secret-key', { algorithm: 'HS256' }); const decoded = jwt.verify(token, 'secret-key', { algorithms: ['HS256'] });
适用场景:
- 单体应用
- 服务端对服务端的认证
- 内部系统通信
2. RS256 (RSA SHA256)
非对称加密算法,使用私钥签名,公钥验证。
特点:
- 安全性更高,私钥不泄露
- 公钥可以公开分发
- 密钥管理相对简单
- 性能较慢
示例:
javascriptconst privateKey = fs.readFileSync('private.key'); const publicKey = fs.readFileSync('public.key'); // 签名(使用私钥) const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' }); // 验证(使用公钥) const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
适用场景:
- 分布式系统
- 公共 API
- 第三方集成
- 需要高安全性的场景
3. ES256 (ECDSA SHA256)
椭圆曲线数字签名算法,使用私钥签名,公钥验证。
特点:
- 签名更小(比 RSA 小约 50%)
- 性能比 RSA 更好
- 安全性高
- 密钥生成速度快
示例:
javascriptconst privateKey = fs.readFileSync('ec-private.key'); const publicKey = fs.readFileSync('ec-public.key'); const token = jwt.sign(payload, privateKey, { algorithm: 'ES256' }); const decoded = jwt.verify(token, publicKey, { algorithms: ['ES256'] });
适用场景:
- 移动应用(减少传输数据量)
- IoT 设备
- 需要高性能的场景
4. PS256 (RSA-PSS SHA256)
RSA-PSS 签名算法,比 RS256 更安全。
特点:
- 提供更强的安全性证明
- 签名大小与 RS256 相同
- 性能与 RS256 相似
适用场景:
- 对安全性要求极高的系统
- 金融、医疗等敏感领域
算法对比
| 算法 | 类型 | 密钥对 | 签名大小 | 性能 | 安全性 | 推荐度 |
|---|---|---|---|---|---|---|
| HS256 | 对称 | 单密钥 | ~32B | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| RS256 | 非对称 | 公私钥 | ~256B | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| ES256 | 非对称 | 公私钥 | ~64B | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| PS256 | 非对称 | 公私钥 | ~256B | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
密钥生成
生成 RSA 密钥对
bash# 生成私钥 openssl genrsa -out private.key 2048 # 生成公钥 openssl rsa -in private.key -pubout -out public.key
生成 ECDSA 密钥对
bash# 生成私钥 openssl ecparam -name prime256v1 -genkey -noout -out ec-private.key # 生成公钥 openssl ec -in ec-private.key -pubout -out ec-public.key
选择建议
选择 HS256 的情况
- 应用规模较小,单服务部署
- 密钥可以安全地存储和共享
- 对性能要求极高
- 内部系统通信
选择 RS256 的情况(推荐)
- 分布式系统,多服务部署
- 需要高安全性
- 公开 API 或第三方集成
- 标准的 JWT 实现
选择 ES256 的情况
- 移动应用或 IoT 设备
- 需要减少传输数据量
- 对性能有较高要求
- 签名大小敏感的场景
选择 PS256 的情况
- 金融、医疗等高安全要求领域
- 需要最强的安全性证明
- 不介意性能开销
安全注意事项
-
永远不要使用
none算法javascript// 危险!不要这样做 const token = jwt.sign(payload, '', { algorithm: 'none' }); -
验证时指定算法
javascript// 安全做法 const decoded = jwt.verify(token, key, { algorithms: ['RS256'] // 明确指定允许的算法 }); -
使用足够强度的密钥
- RSA: 至少 2048 位,推荐 3072 或 4096 位
- ECDSA: 至少 P-256,推荐 P-384 或 P-521
- HMAC: 至少 256 位
-
定期轮换密钥
- 建议每 6-12 个月轮换一次
- 实现密钥版本管理
- 支持多密钥验证(平滑过渡)
-
安全存储密钥
- 使用环境变量或密钥管理服务
- 不要将密钥提交到代码仓库
- 限制密钥的访问权限
性能优化建议
- 缓存公钥: 验证时缓存公钥,避免重复读取
- 使用 ES256: 在安全性和性能之间取得平衡
- 批量验证: 对于大量 token,考虑批量验证
- 异步验证: 使用异步 API 避免阻塞
通过合理选择签名算法,可以在安全性、性能和易用性之间找到最佳平衡。