乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • JWT 基础

    • JWT 概述
    • JWT 结构详解
  • 签名与加密

    • JWS 签名基础
    • RS256与ES256签名
    • JWE 加密
  • 密钥管理

    • JWK 与密钥管理
  • 算法原理

    • 核心算法详解
  • 实战与安全

    • JWT 实际应用
    • JWT 安全攻防

RS256与ES256签名

在上一章中,我们了解了使用 HMAC(Keyed-Hash Message Authentication Code,密钥散列消息认证码) 的 HS256 签名。HMAC 需要通信双方共享同一个密钥,任何能验证令牌的人也能伪造令牌。当广州飞翔科技(learnto.cn)需要向多个外部合作伙伴分发身份令牌时,共享密钥方案就不再适用。架构师白歌提出:"我们需要一种 一对多(one-to-many) 的签名方案——签发方独自持有私钥,验证方只持有公钥。"

本章将介绍两种非对称签名算法: RS256 (RSA + SHA-256)和 ES256 (ECDSA + P-256 + SHA-256),并结合飞翔科技的实际场景讲解其用法。


RS256:RSA 签名 + SHA-256

RS256 全称 RSASSA-PKCS1-v1_5 using SHA-256 ,即使用 RSA(Rivest–Shamir–Adleman) 算法的签名变体配合 SHA-256(Secure Hash Algorithm 256-bit) 哈希函数。

核心原理

RSA 是一种 非对称密码学(asymmetric cryptography) 算法,它生成一对密钥:

  • 私钥(private key) :仅由签发方持有,用于 创建签名(sign) 。
  • 公钥(public key) :可以公开分发给任意验证方,用于 验证签名(verify) 。

飞翔科技场景 :白歌在设计联邦身份认证系统时,决定由飞翔科技的认证中心统一签发令牌。各业务线(电商、社区、内容平台)只需部署公钥即可验证用户身份,无需知道私钥。即使某个业务线的服务器被攻破,攻击者也无法伪造新的有效令牌。

使用 OpenSSL 生成 RSA 密钥对

小崔在本地开发环境需要一套测试密钥,他使用 OpenSSL 快速生成:

# 生成 2048 位 RSA 私钥
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

# 从私钥派生对应的公钥
openssl rsa -pubout -in private_key.pem -out public_key.pem

生成的 private_key.pem 和 public_key.pem 都是 PEM 格式的文本文件,可直接复制到代码中使用。

RS256 签名与验证代码

以下示例使用 JavaScript 的 jsonwebtoken 库:

import jwt from 'jsonwebtoken';

const payload = {
  sub: "feixiang-user-10086",
  name: "赵鸣",
  department: "产品部",
  role: "content_operator"
};

// 使用私钥签名
const privateRsaKey = `<YOUR-PRIVATE-RSA-KEY>`;
const signed = jwt.sign(payload, privateRsaKey, {
  algorithm: 'RS256',
  expiresIn: '2h'
});

// 使用公钥验证
const publicRsaKey = `<YOUR-PUBLIC-RSA-KEY>`;
const decoded = jwt.verify(signed, publicRsaKey, {
  algorithms: ['RS256']  // 明确指定算法,防止签名剥离攻击
});

console.log(decoded);

安全提示 :algorithms 选项必须显式指定。如果省略,攻击者可能剥离签名、修改头部为 alg: none 或更弱的算法,从而绕过验证。


ES256:ECDSA 签名 + P-256 + SHA-256

ES256 全称 ECDSA using P-256 and SHA-256 ,即使用 ECDSA(Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法) 配合 P-256 曲线和 SHA-256 哈希函数。

核心原理

ECDSA 与 RSA 一样属于非对称签名算法,也使用私钥签名、公钥验证。但两者的数学基础不同:

  • RSA 基于 大整数分解(integer factorization) 难题。
  • ECDSA 基于 椭圆曲线离散对数(elliptic curve discrete logarithm) 难题。

在同等安全强度下,ECDSA 的密钥尺寸远小于 RSA。例如,256 位的 ECDSA 密钥与 3072 位的 RSA 密钥提供相近的安全性,但前者的签名结果更短、计算更快,特别适合移动端和物联网设备。

使用 OpenSSL 生成 ECDSA 密钥对

小崔对比测试时,用 OpenSSL 生成 ECDSA 密钥:

# 生成 P-256 曲线私钥(prime256v1 即 JWA 规范中的 P-256)
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_private_key.pem

# 从私钥派生公钥
openssl ec -in ecdsa_private_key.pem -pubout -out ecdsa_public_key.pem

打开生成的文件可以看到,ECDSA 密钥的文本量明显比 RSA 少得多。

ES256 签名与验证代码

import jwt from 'jsonwebtoken';

const payload = {
  sub: "feixiang-user-10010",
  name: "杨英",
  department: "运营部",
  role: "activity_operator"
};

// 使用 ECDSA 私钥签名
const privateEcdsaKey = `<YOUR-PRIVATE-ECDSA-KEY>`;
const signed = jwt.sign(payload, privateEcdsaKey, {
  algorithm: 'ES256',
  expiresIn: '2h'
});

// 使用 ECDSA 公钥验证
const publicEcdsaKey = `<YOUR-PUBLIC-ECDSA-KEY>`;
const decoded = jwt.verify(signed, publicEcdsaKey, {
  algorithms: ['ES256']
});

console.log(decoded);

注意 :ECDSA 签名每次都会产生不同的字节序列(因为引入了随机数),但验证结果始终一致。某些旧版库可能对签名格式有严格要求,需确保使用 DER 编码的 ASN.1 格式。


算法对比:HMAC vs RSA vs ECDSA

小崔在内部技术分享会上,向团队整理了一份三种签名算法的对比表:

对比维度HS256 (HMAC)RS256 (RSA)ES256 (ECDSA)
密钥类型对称密钥(single secret)非对称密钥对(key pair)非对称密钥对(key pair)
签名速度快较慢快
验证速度快较快较快
签名长度256 位2048 位512 位
密钥尺寸短(任意字符串)长(2048 位约 1.6KB)极短(256 位约 32 字节)
分发场景一对一(内部服务)一对多(开放平台)一对多(移动端/IoT)
安全性假设密钥不泄露大整数分解难题椭圆曲线离散对数难题
典型用途微服务内部通信联邦身份认证、OAuth移动 App、带宽受限环境

飞翔科技决策 :

  • 白歌为 联邦身份认证中心 选择 RS256 ,因为公钥易于分发给多个合作伙伴,且兼容性好。
  • 小崔为 乐途运动 App 的客户端令牌选择 ES256 ,因为移动端网络带宽有限,更短的签名能减少传输开销。
  • 李眉在 内部容器网络 的服务间调用中继续使用 HS256 ,因为共享密钥管理简单、性能最优。

选择合适的算法

白歌在架构评审会上总结道:"没有绝对最好的算法,只有最适合场景的算法。"

  • 如果你的系统需要 多个验证方 且不能让他们拥有签发能力,选择 RS256 或 ES256 。
  • 如果你的部署环境 带宽或存储极度受限 (如物联网设备、小程序),优先选择 ES256 。
  • 如果你的服务完全在 可信内部网络 中运行,且追求极致性能, HS256 仍然是一个务实的选择。

无论选择哪种算法,请务必在验证时 显式声明 algorithms 白名单 ,这是防止算法混淆攻击(algorithm confusion attack)的最后一道防线。

上一页
JWS 签名基础
下一页
JWE 加密