3. JWT 签名算法:HS256 对称签名原理、RS256 非对称签名原理、算法选择策略

JWT 的签名算法是保证令牌完整性与可信性的核心。签名算法决定了 Token 在传输过程中是否被篡改,以及接收方能否验证签发方的身份。本章深入剖析最常用的两种算法:HS256(对称签名)与 RS256(非对称签名),并给出生产环境下的算法选择策略。

3.1 HS256 对称签名原理

HS256(HMAC with SHA-256)使用同一个密钥进行签名和验签。签发方和接收方必须事先共享该密钥,且密钥不得泄露。

签名与验签流程

  1. 准备输入:将 JWT 的 Header 和 Payload 分别进行 Base64URL 编码,用点号连接。
  2. 计算签名:使用 HMAC-SHA256 算法,以共享密钥对上述字符串计算摘要,得到签名。
  3. 组装 Token:将签名进行 Base64URL 编码,附加到前两部分之后。
  4. 验签:接收方使用相同的共享密钥,对 Header.Payload 重新计算 HMAC,比对结果是否一致。
核心特征:签名 = HMAC-SHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
安全提示:共享密钥必须具有足够的熵(至少 256 位随机数),且通过安全的带外渠道(如密钥管理服务、配置文件加密)分发。切勿将密钥硬编码在代码仓库中。
HS256 对称签名与验签流程 HS256 对称签名与验签流程 签发方 共享密钥 (Secret) 接收方 ① Header + Payload ② HMAC-SHA256 签名 ③ 生成 JWT Token ① 解析 Header.Payload ② 重新计算 HMAC ③ 比对签名是否一致 注意:共享密钥必须安全存储,任何一方泄露都会导致整个认证体系失效。

3.2 RS256 非对称签名原理

RS256(RSA Signature with SHA-256)使用一对密钥:私钥(Private Key)用于签名,公钥(Public Key)用于验签。私钥由签发方保管,公钥可以公开分发给所有接收方。

签名与验签流程

  1. 签发方:使用私钥对 Header.Payload 进行 RSA-SHA256 签名。
  2. 接收方:使用公钥验证签名,无需持有私钥。
  3. 密钥分发:公钥可通过 JWKS(JSON Web Key Set)端点、配置文件或证书方式发布。
核心特征:签名 = RSA-SHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), privateKey )
验签 = RSA-SHA256_verify( signature, publicKey )
性能注意:RS256 签名速度比 HS256 慢约 10-100 倍,但验签速度相对较快。在需要频繁签发的场景(如高并发登录)需评估性能影响。
RS256 非对称签名与验签流程 RS256 非对称签名与验签流程 签发方 私钥 (Private Key) 公钥 (Public Key) 接收方 ① Header + Payload ② 私钥 RSA-SHA256 签名 ③ 生成 JWT Token ① 解析 Header.Payload ② 公钥验证签名 ③ 返回验证结果 公钥可公开分发,私钥必须严格保密。推荐使用 JWKS 端点动态获取公钥。

3.3 算法选择策略

选择 HS256 还是 RS256 取决于系统架构、安全要求和运维能力。下表从多个维度进行对比:

对比维度 HS256(对称) RS256(非对称)
密钥管理 单一共享密钥,分发困难 私钥仅签发方持有,公钥可公开
安全性 密钥泄露则整个系统失效 私钥泄露风险低,公钥泄露无影响
签名性能 快(纯哈希运算) 慢(RSA 模幂运算)
验签性能 快(与签名相同) 较快(公钥指数小)
密钥轮换 需要同步更新所有服务 仅需更新公钥,支持 JWKS 动态轮换
适用场景 单体应用、内部微服务、信任域内 开放 API、第三方集成、跨信任域

生产环境推荐策略

  • 内部微服务通信:优先使用 HS256,性能高且密钥管理简单(如通过 Kubernetes Secret 共享)。
  • 开放 API / 第三方集成:必须使用 RS256,公钥可通过 JWKS 端点动态获取,避免密钥分发风险。
  • 多服务 / 多团队:推荐 RS256 + JWKS,每个服务独立管理密钥,支持无感轮换。
  • 移动端 / 前端:只能使用 RS256,因为客户端无法安全存储共享密钥。
最佳实践:不要使用 HS256 作为跨信任域的认证方案。一旦共享密钥泄露,攻击者可以伪造任意用户的 Token。RS256 配合 JWKS 是业界标准的微服务安全架构。

代码示例:HS256 与 RS256 签名对比(Node.js + jsonwebtoken)

const jwt = require('jsonwebtoken');

// ===== HS256 对称签名 =====
const secret = 'your-256-bit-secret';
const tokenHS = jwt.sign(
  { userId: 123, role: 'admin' },
  secret,
  { algorithm: 'HS256', expiresIn: '1h' }
);
// 验签
const decodedHS = jwt.verify(tokenHS, secret);
console.log('HS256 验签通过:', decodedHS);

// ===== RS256 非对称签名 =====
const fs = require('fs');
const privateKey = fs.readFileSync('private.pem');
const publicKey = fs.readFileSync('public.pem');

const tokenRS = jwt.sign(
  { userId: 456, role: 'user' },
  privateKey,
  { algorithm: 'RS256', expiresIn: '2h' }
);
// 验签
const decodedRS = jwt.verify(tokenRS, publicKey);
console.log('RS256 验签通过:', decodedRS);
安全警告:生产环境中,HS256 的密钥长度至少 256 位;RS256 的私钥推荐使用 2048 位或更高。切勿使用弱密钥或过短的 RSA 密钥(如 1024 位)。