YAOTU INSIGHTS

PyJWT 密钥获取实战:使用 cryptography 从 x509 证书中提取公钥/私钥完成 JWT 签名与验签

PyJWT 密钥获取实战:使用 cryptography 从 x509 证书中提取公钥/私钥完成 JWT 签名与验签
后端认证鉴权【免费下载链接】pyjwtJSON Web Token implementation in Python项目地址https://gitcode.com/gh_mirrors/py/pyjwt点击查看免费下载本文讲解如何借助cryptography库的load_pem_x509_certificate()函数从 PEM 格式的 x509 证书中提取公钥与私钥对象并将它们直接用于 PyJWT 的 RS256、ES256、EdDSA 等非对称算法的 token 签发与验证。读完本文你将掌握「证书 → 密钥对象 → JWT 签名/验签」的完整链路并了解 PyJWT 内部对 PEM 密钥与证书的解析与校验逻辑。场景为什么需要从 x509 证书中提取密钥PyJWT 的对称算法HS256/HS384/HS512直接使用一段共享的字节串作为密钥而非对称算法RS256、RS384、RS512、ES256、ES384、ES512、PS256、EdDSA 等则需要 RSA、EC 或 Ed25519/Ed448 密钥对象参与签名与验签。在真实生产环境中这些非对称密钥往往不是孤立存放的而是以x509 证书的形式分发企业/组织签发的 TLS 证书链中携带公钥服务端用它向客户端证明身份自签名的测试证书如仓库 tests/keys/testkey_rsa.cer同时承载公钥与私钥用于本地开发与单元测试当 JWT 签发方与验证方通过证书交换信任关系时验证方只需要从对方的证书里取出公钥即可完成 token 验签。此时最直接的做法就是解析证书对象再从证书对象中取出密钥。前置条件安装 cryptographyPyJWT 本身并不内联实现 RSA/EC/EdDSA 等密码学原语而是委托给cryptography库。查看源码 jwt/algorithms.py 中requires_cryptography集合jwt/algorithms.py#L126-L139可以看到RS256/RS384/RS512/ES256/ES256K/ES384/ES521/ES512/PS256/PS384/PS512/EdDSA全部依赖cryptography只有 HS256/HS384/HS512 与none可以在不安装它的情况下工作。因此使用证书提取密钥并配合非对称算法时需要先安装$ pip install PyJWT cryptographyPyJWT主包安装方式见 README.rstpip install PyJWT。核心方法load_pem_x509_certificate() 提取公钥/私钥官方 FAQdocs/faq.rst给出的解决方案非常直接使用cryptography.x509中的load_pem_x509_certificate()加载 PEM 格式证书然后通过证书对象的public_key()与private_key()方法取出对应密钥。从内存字节加载证书from cryptography.x509 import load_pem_x509_certificate cert_str b-----BEGIN CERTIFICATE-----MIIDETCCAfm... cert_obj load_pem_x509_certificate(cert_str) public_key cert_obj.public_key() private_key cert_obj.private_key()要点说明load_pem_x509_certificate()的入参是bytes 类型的 PEM 证书内容以-----BEGIN CERTIFICATE-----开头、-----END CERTIFICATE-----结尾。传入str会报类型错误传真实文件内容时务必以二进制模式读取。public_key()返回RSAPublicKey/EllipticCurvePublicKey/Ed25519PublicKey等cryptography公钥对象可用于验签。private_key()返回对应的私钥对象可用于签名。注意该方法仅在证书本身包含私钥时才可用——典型场景是自签名证书或带私钥的证书/密钥对文件由 CA 签发的常规终端实体证书通常不含私钥此时调用private_key()会抛出异常私钥应另行从私钥文件中加载见下文。从证书文件加载实际开发中密钥通常存放在文件中配合pathlib或内置open读取from pathlib import Path from cryptography.x509 import load_pem_x509_certificate cert_bytes Path(server_cert.pem).read_bytes() cert_obj load_pem_x509_certificate(cert_bytes) public_key cert_obj.public_key() # 用于 JWT 验签仓库测试 tests/test_algorithms.py 中正是采用这种方式加载测试证书testkey_rsa.cer后再调用public_bytes(Encoding.DER)将其转换为 DER 格式用于防御性测试可作为文件加载的标准写法参考。与 PyJWT 实战结合签发与验证 JWT提取出的cryptography密钥对象可以直接作为jwt.encode()与jwt.decode()的key参数使用——PyJWT 的算法层原生接受这类密钥对象。用证书中的公钥验证 token验签端import jwt from pathlib import Path from cryptography.x509 import load_pem_x509_certificate # 1. 从对方/自己服务的证书中取出公钥 cert_bytes Path(server_cert.pem).read_bytes() public_key load_pem_x509_certificate(cert_bytes).public_key() # 2. 验证 token必须显式指定允许的算法白名单 claims jwt.decode( token, keypublic_key, algorithms[RS256], # 根据实际签名算法选择 RS256/ES256/EdDSA 等 ) print(claims)用证书中的私钥签发 token签名端import jwt from pathlib import Path from cryptography.x509 import load_pem_x509_certificate # 仅当证书本身携带私钥时可用如自签名证书 private_key load_pem_x509_certificate( Path(server_cert.pem).read_bytes() ).private_key() token jwt.encode( {sub: user-123, role: admin}, keyprivate_key, algorithmRS256, )底层原理PyJWT 如何接受这些密钥对象在签名流程中jwt/api_jws.py的编码逻辑会先通过get_algorithm_by_name()拿到对应算法对象再调用alg_obj.prepare_key(key)对密钥做归一化处理jwt/api_jws.py#L199-L202。以 RSA 为例RSAAlgorithm.prepare_key()jwt/algorithms.py#L530-L561的逻辑是如果传入的 key 已经是RSAPrivateKey/RSAPublicKey类型的cryptography对象直接返回from cryptography.x509提取出的正是这种对象因此无需二次转换如果传入的是 PEM 字符串/字节则依次尝试load_pem_private_key()与load_pem_public_key()解析解析失败抛出InvalidKeyError。这也意味着从证书中提取的公钥/私钥对象与直接传入 PEM 字符串open(key.pem).read()在 PyJWT 内部是等效的两条路径——前者适合密钥以证书形式托管的场景后者适合密钥独立以 PEM 文件存放的场景。将提取出的密钥导出为 PEM 再传入如果希望显式控制密钥格式例如打印、归档或传给不支持对象形式的 API可以用public_bytes()导出from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat pem public_key.public_bytes( encodingEncoding.PEM, formatPublicFormat.SubjectPublicKeyInfo, ) token_claims jwt.decode(token, keypem, algorithms[RS256])注意事项与安全边界1. 证书不能当作 HMAC 密钥使用把证书内容直接当作 HS256 的密钥是常见误区。PyJWT 对此有专门防御HMACAlgorithm._is_der_key()jwt/algorithms.py#L328-L344会尝试用x509.load_der_x509_certificate()识别 DER 证书一旦命中就抛出InvalidKeyError错误信息明确提示证书不应被用作 HMAC 密钥。仓库测试 tests/test_algorithms.py#L348-L356test_hmac_prepare_key_rejects_der_certificate验证了这一行为将证书转为 DER 后传给HMACAlgorithm.prepare_key()必然抛错。这是防止算法混淆攻击把非对称密钥降级为对称密钥的关键防线。2. 私钥提取的前提Certificate.private_key()只在证书携带私钥常见于自签名证书或导出时同时包含私钥的证书文件时可用CA 签发的证书只含公钥私钥需通过load_pem_private_key()从独立的.key/.pem私钥文件加载PyJWT 自身在 jwt/algorithms.py#L548-L552 也正是这样解析 PEM 私钥的。私钥属于敏感材料签发场景应存放于受控环境如密钥管理服务、受保护文件系统切勿随证书公开分发。3. 算法白名单必须显式指定jwt.decode()要求显式传入algorithms参数jwt/api_jws.py#L247-L250 会在缺失时抛出DecodeError。这是为了防止攻击者篡改 token 头部中的alg字段引发算法混淆务必只允许你信任的算法。4. 曲线与算法匹配从证书中提取出的 EC 公钥必须与算法约定的曲线匹配。例如 ES256 对应 P-256secp256r1、ES384 对应 P-384PyJWT 的ECAlgorithm._validate_curve()jwt/algorithms.py#L716-L725会在密钥曲线不符时抛出InvalidKeyError。RSA 密钥还受最小长度检查约束_MIN_KEY_SIZE 2048低于该值会触发InsecureKeyLengthWarning见 jwt/algorithms.py#L516-L528。扩展阅读与仓库证据官方 FAQ 原文docs/faq.rst算法注册表与requires_cryptography依赖清单jwt/algorithms.pyRSA 密钥解析实现prepare_key/load_pem_private_key/load_pem_public_keyjwt/algorithms.py证书防御性测试拒绝证书作为 HMAC 密钥tests/test_algorithms.py测试证书文件tests/keys/testkey_rsa.cerJWT 编码/验证主流程jwt/api_jws.py总结一下load_pem_x509_certificate()是从证书中提取公钥/私钥的标准入口提取出的cryptography密钥对象可直接交付给 PyJWT 的非对称算法完成 JWT 签发与验签同时要注意私钥是否真的存在于证书中、算法与曲线/密钥长度的匹配以及永远不要把证书内容当作 HMAC 对称密钥。赞分享后端认证鉴权【免费下载链接】pyjwtJSON Web Token implementation in Python项目地址https://gitcode.com/gh_mirrors/py/pyjwt点击查看免费下载相关推荐cryptography 库 RSA 公钥密码完全指南密钥生成、序列化、签名与加密实战cryptography 库 RSA 公钥密码完全指南密钥生成、序列化、签名与加密实战 RSA 是 cryptography 库中历史最悠久、使用最广泛的非对密码学Tink Java JWT 签名示例实战从密钥生成到签发与验证Tink Java JWT 签名示例实战从密钥生成到签发与验证 本指南以 Tink 官方 Java JWT 签名示例 java_src/examples/j密码学Tink Python JWT 签名实战密钥生成、Token 签发与 JWK Set 验证完整指南Tink Python JWT 签名实战密钥生成、Token 签发与 JWK Set 验证完整指南 导读 本文以 Tink 官方 Python JWT 签名示密码学应用安全上一篇CoffeeScript 0.3.2 版本解析property 简写语法与从 Narwhal 到 Node.js 的引擎切换下一篇lark-cli 多维表格表单提交实战base form-submit 命令完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考