生成JWT时必须显式指定algorithm(如HS256),禁用none算法;密钥须从环境变量加载,payload不存敏感信息且设exp;校验需分捕ExpiredSignatureError等异常,并传algorithms和audience参数。

生成JWT时必须指定algorithm且避免用none
PyJWT默认不强制校验签名算法,如果生成时传入algorithm="none"或未指定algorithm却用key=None,会产出无签名的JWT——攻击者可随意篡改payload内容。生产环境必须显式指定HS256、RS256等安全算法,并配对使用密钥。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 始终显式传入
algorithm参数,例如jwt.encode(payload, secret_key, algorithm="HS256") - 绝不要在生产中使用
algorithm="none",该选项仅用于调试或兼容遗留系统 - 若用RSA签名,私钥用于
encode(),公钥用于decode(),密钥格式需为PEM字符串(含-----BEGIN PRIVATE KEY-----等头尾) -
secret_key不能硬编码,应从环境变量或密钥管理服务加载,长度建议≥32字节(HS256)
校验JWT必须捕获所有可能异常并检查exp和aud
PyJWT的jwt.decode()在遇到无效签名、过期、缺失字段等问题时抛出不同异常,但开发者常只捕获InvalidTokenError,漏掉ExpiredSignatureError或InvalidAudienceError,导致令牌被绕过校验。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须分别捕获
ExpiredSignatureError、InvalidSignatureError、InvalidAudienceError、InvalidIssuerError等具体异常,而非笼统的Exception - 务必传入
audience参数(如audience="my-api"),并在payload中预置"aud": "my-api" - 设置
options={"require_exp": True, "verify_exp": True}确保强制校验exp字段存在且未过期 - 校验时传入
algorithms=["HS256"]明确限定允许的算法,防止算法混淆攻击
encode()和decode()的leeway参数不是用来放宽时间校验的借口
有些开发者为应付服务器时钟偏差,盲目设置leeway=60(秒),结果让过期1分钟内的令牌仍能通过校验——这实质上扩大了有效窗口,削弱了exp的安全意义。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
leeway仅用于补偿NTP同步误差,值应≤5秒;若时钟偏差持续超过此范围,应修复服务器时间同步机制,而非调高leeway - 不要在
encode()中设leeway(它只对decode()生效) - 若需支持“刷新令牌”逻辑,应单独设计
refresh_token流程,而非依赖leeway延长访问令牌生命周期
PyJWT 2.0+版本废弃verify=True/False,必须用options控制校验行为
旧代码中常见的jwt.decode(token, key, verify=False)在PyJWT ≥2.0会报错,因为verify参数已被移除。直接跳过签名校验等于完全放弃JWT核心安全机制。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 升级后必须改用
options={"verify_signature": True, "verify_exp": True, ...}精细控制各校验项 -
options={"verify_signature": False}仅限单元测试或调试,生产环境禁止启用 - 检查项目依赖:运行
pip show pyjwt确认版本,若为1.x请尽快升级,因1.x存在已知漏洞(如CVE-2022-29038)
最易被忽略的是aud和iss字段的双向校验:生成时写入,校验时显式比对。很多人只设aud却不传audience参数,或把iss写成固定字符串却没配issuer,结果这些字段形同虚设。


















