JWS 签名由两个 32 字节大端序整数 r 和 s 拼接后经 base64url 编码而成(86 个字符)。用 OpenSSL、Java 默认的 SHA256withECDSA、Go 的 ecdsa.SignASN1 或 Node 默认的 crypto.sign() 签名,得到的却是 DER,验证者会拒绝它;应请求 IEEE P1363 格式的输出,或者自行转换格式。密钥是 crv 为 P-256 的 EC JWK。
ES256 是通行密钥(COSE −7)、DPoP 证明、Apple 的 App Store Connect 和 APNs 提供商令牌以及许多现代身份提供商的默认算法,因为浏览器的 WebCrypto、Secure Enclave、TPM 和云 KMS 都支持 P-256。签名速度很快(在 Apple M4 Max 的单个核心上,OpenSSL 3.6.5 每秒约可完成 87,000 次签名),令牌也比使用 2048 位密钥的 RS256 令牌短约 250 个字符。
2022年的一个深刻教训:Java 15 到 18 会对任意消息和密钥接受全零的 ECDSA 签名(CVE-2022-21449,“Psychic Signatures”),导致伪造的 ES256 JWT 也能通过验证。要及时为运行时打补丁,并确保验证者拒绝取值不在 1…n−1 范围内的 r 或 s。