JWK 与密钥管理
当广州飞翔科技(learnto.cn)的微服务集群从 5 个扩展到 50 个时,后端开发小崔遇到了一个头疼的问题:每个服务都硬编码了验证 JWT 的公钥,轮换密钥时需要重新发布所有服务。架构师白歌看了一眼他的代码说:"你需要 JWK(JSON Web Key,JSON Web 密钥) 和 JWKS(JSON Web Key Set,JSON Web 密钥集) 。把密钥集中管理,通过端点分发,服务启动时动态拉取。"
本章将介绍 JWK 的结构、密钥类型、JWKS 集合,以及 JWS/JWE 头部中引用密钥的各种声明。
JWK 的结构
JWK 是一个 JSON 对象,包含描述密钥所需的一系列参数。不同密钥类型的参数各不相同,但以下通用参数适用于所有 JWK:
| 参数 | 全称 | 说明 |
|---|---|---|
kty | Key Type(密钥类型) | 必需。区分密钥类型:EC(椭圆曲线)、RSA(RSA 密钥)、oct(对称密钥) |
use | Public Key Use(公钥用途) | 可选。sig 表示用于签名,enc 表示用于加密 |
key_ops | Key Operations(密钥操作) | 可选。详细指定用途,如 sign、verify、encrypt、decrypt、wrapKey、unwrapKey 等。不应与 use 同时使用 |
alg | Algorithm(算法) | 可选。打算与该密钥配合使用的算法,如 RS256、ES256、A256GCM |
kid | Key ID(密钥标识符) | 可选。密钥的唯一标识符,用于在 JWKS 中快速定位特定密钥 |
x5u | X.509 URL | 可选。指向 PEM 编码的 X.509 证书或证书链的 URL |
x5c | X.509 Certificate Chain | 可选。Base64 编码的 X.509 DER 证书数组 |
x5t | X.509 Certificate SHA-1 Thumbprint | 可选。证书的 SHA-1 指纹 |
x5t#S256 | X.509 Certificate SHA-256 Thumbprint | 可选。证书的 SHA-256 指纹 |
示例 JWK(椭圆曲线公钥):
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "feixiang-ec-key-01"
}
三种密钥类型
JWA(JSON Web Algorithms)规范定义了三种主要的 JWK 密钥类型:
EC:椭圆曲线密钥(Elliptic Curve Key)
用于 ECDSA 签名和 ECDH 密钥协商。核心参数包括:
crv:曲线名称,如P-256、P-384、P-521。x、**y** :公钥的坐标点。d:私钥值(仅私钥 JWK 包含)。
飞翔科技场景 :小崔为乐途运动 App 生成了一套 ECDSA 密钥,公钥以 JWK 格式发布到密钥端点,供移动端 SDK 下载验证令牌。
RSA:RSA 密钥
用于 RSASSA 签名和 RSAES 加密。核心参数包括:
n:模数(modulus),大整数。e:公钥指数(public exponent),通常为AQAB(即 65537)。d:私钥指数(private exponent,仅私钥)。p、q、dp、dq、qi:CRT(中国剩余定理)参数,加速私钥运算(仅私钥)。
示例 RSA 公钥 JWK:
{
"kty": "RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB",
"alg": "RS256",
"kid": "feixiang-rsa-key-2024"
}
oct:对称密钥(Octet Sequence Key)
用于 HMAC 签名和 AES 加密。只有一个核心参数:
k:密钥值,Base64-URL 编码。
示例对称密钥 JWK:
{
"kty": "oct",
"k": "GawgguFygrWKfh7pI8l3fQ",
"alg": "HS256",
"kid": "feixiang-hmac-key-internal"
}
安全提示 :对称密钥的 JWK 应严格限制访问权限,仅在受信任的服务间共享。飞翔科技的内部 Kubernetes 集群中,oct 类型的 JWK 通过 Sealed Secrets 加密存储。
JWKS:JSON Web Key Set
单个 JWK 可以描述一把密钥,但实际系统中通常需要多把密钥(例如新旧密钥同时存在以实现平滑轮换)。 JWKS 就是一个包含多个 JWK 的 JSON 对象,顶层有一个 keys 数组:
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
"y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
"use": "enc",
"kid": "feixiang-ec-key-01"
},
{
"kty": "RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB",
"alg": "RS256",
"kid": "feixiang-rsa-key-2024"
}
]
}
飞翔科技场景 :小崔在
https://learnto.cn/.well-known/jwks.json部署了 JWKS 端点。所有内部服务启动时自动拉取该端点,根据kid匹配令牌头部中的密钥标识符,完成验证。当白歌决定轮换 RSA 密钥时,只需在 JWKS 中新增一个kid为feixiang-rsa-key-2025的条目,旧密钥保留一段时间供未过期令牌使用,服务无需重新部署。
JWS 头部中的密钥引用声明
JWS 和 JWE 规范提供了多种在头部中引用密钥的方式,使验证方无需硬编码密钥:
| 声明 | 全称 | 用途 |
|---|---|---|
jku | JWK Set URL | 指向 JWKS 端点的 URI。验证方通过 HTTP GET 获取密钥集合 |
jwk | JSON Web Key | 直接将公钥以 JWK 格式嵌入令牌头部 |
kid | Key ID | 密钥标识符,与 JWKS 中的 kid 匹配以选取特定密钥 |
x5u | X.509 URL | 指向 PEM 编码的 X.509 证书链的 URL |
x5c | X.509 Certificate Chain | 直接在头部中嵌入 Base64 编码的 X.509 证书数组 |
x5t | X.509 Certificate SHA-1 Thumbprint | 用 SHA-1 指纹引用证书 |
x5t#S256 | X.509 Certificate SHA-256 Thumbprint | 用 SHA-256 指纹引用证书(推荐) |
飞翔科技场景 :
- 小崔在内部服务间使用
kid+jku的组合:令牌头部携带kid,验证方从统一的 JWKS 端点拉取密钥集合,按kid索引找到正确的公钥。- 白歌在与外部合作伙伴对接时,选择在头部中直接嵌入
jwk,减少对方系统的依赖,但代价是令牌体积增大。- 李眉在支付网关使用
x5c嵌入完整的证书链,因为金融合规要求提供可审计的证书信任链。
密钥管理的最佳实践
小崔在飞翔科技内部 wiki 中整理了 JWK/JWKS 的使用规范:
- 始终使用
kid:即使只有一个密钥,也要设置kid,为未来的密钥轮换预留空间。 - 优先使用
jku而非硬编码 :验证方应从可信的 JWKS 端点动态获取公钥,而不是把公钥写死在配置文件里。 - HTTPS 传输
jku和x5u:获取密钥的链路必须使用 TLS,防止中间人篡改公钥。 - 密钥轮换策略 :新密钥加入 JWKS 后,旧密钥保留一个令牌最大生命周期(如 24 小时)再移除,避免正在流通的令牌失效。
- 私钥永不离开签发服务 :JWK 格式的私钥(包含
d参数)只存在于签发服务的内存或安全密钥库(HSM、KMS)中,绝不通过 API 暴露。
白歌的总结 :"JWT 的安全性不只在算法选择,更在密钥管理。JWK 和 JWKS 给了我们一个标准化的密钥分发框架,但框架本身不能替代安全运维——HTTPS、访问控制、密钥轮换,一个都不能少。"
小结
- JWK 是 JSON 格式的密钥描述,统一了 EC、RSA、对称密钥的表示方式。
- JWKS 通过
keys数组管理多个密钥,是微服务架构中实现密钥轮换的基础设施。 - JWS/JWE 头部声明 (
jku、jwk、kid、x5u、x5c、x5t等)提供了灵活的密钥引用机制,使验证方能够动态定位正确的公钥。 - 飞翔科技通过统一的 JWKS 端点,实现了 50+ 微服务的密钥集中管理,大幅降低了运维复杂度。