“JWT 安全吗?“——安全性取决于你怎么用。九成问题出在一个误解上:JWT 是签名,不是加密。token 里的内容任何人都能看。
JWT 长什么样
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEyMyx
← header ← payload
LCJleHAiOjE3NjM0NTYwMH0.sflKxwRJSMeKKF2Q
T4fwpMeJf36POk6yJV_adQssw5c
↑ signature
三段用 . 分隔:
- Header —
{"alg":"HS256","typ":"JWT"}Base64URL - Payload —
{"userId":123,"exp":1763456000}Base64URL - Signature — HMAC-SHA256(
header.payload, secret)
前两段只是编码,不是加密。粘进解析工具秒看明文。
误解一:payload 加密过了
没有。Base64URL 是可逆编码,浏览器控制台一行就解:
atob('eyJ1c2VySWQiOjEyM30')
// '{"userId":123}'
所以密码、完整身份证、银行卡号绝对不能放 payload。放了等于在数据库外面贴张便利贴。
误解二:签名能阻止篡改
能——但前提是服务端真的校验了签名。历史上有两个经典漏洞:
alg: none 绕过
JWT 规范允许 alg: "none" 表示”不签名”。部分库在校验时傻乎乎地按 header 里的 alg 来——攻击者把 header 改成 {"alg":"none"}、签名段留空,payload 随便改(比如把 role:"user" 改成 role:"admin"),服务端居然通过。
防御:服务端白名单签名算法,jwt.verify(token, secret, { algorithms: ['HS256'] })——把 algorithms 写死,别信 header。
HS256 / RS256 混淆攻击
- RS256 用公钥验证、私钥签发
- HS256 用同一个 secret签发和验证
若服务端配成”验证时 alg 取 header”,攻击者:
- 拿到你公开的 RS256 公钥
- 构造一个 token,header 写
{"alg":"HS256"} - 用那把公钥当作 HS256 的 secret 签名
- 服务端按 HS256 校验,secret 正好是公钥——验证通过
防御:同上,算法写死别跟着 header 走。
误解三:JWT 可以”登出”
标准 JWT 是无状态的,只要签名有效、没到期,服务端就认。“登出”在纯 JWT 下实际上做不到。
常见折中:
- 短过期时间(15 分钟)+ refresh token 机制
- 服务端黑名单:已退出的
jti存 Redis,到期前拦截 - token 版本号:数据库里存 user.tokenVersion,payload 带上;改密码时 tokenVersion+1 让所有老 token 失效
把 JWT 当 session 用、设 7 天过期、不带黑名单——被盗号后只能干等七天。
误解四:JWT 是 OAuth
不是。OAuth 是授权协议,JWT 是token 格式。OAuth 可以用 JWT 做 access token,也可以用别的(比如随机字符串 + 服务端 session)。反过来 JWT 也能单独用——很多简单后端自签自验不走 OAuth。
标准 claim 速查
Payload 里这些 key 是 RFC 7519 定义的”注册 claim”,别随便占用:
| claim | 全称 | 含义 |
|---|---|---|
iss | Issuer | 签发方 |
sub | Subject | token 主体(通常 userId) |
aud | Audience | 预期接收方 |
exp | Expiration Time | 过期时间(Unix 秒) |
nbf | Not Before | 生效时间 |
iat | Issued At | 签发时间 |
jti | JWT ID | 唯一 ID(用于黑名单) |
其他业务字段随便加,但建议用短名字(payload 越小 token 越短)。
一次 JWT 体检清单
- 算法白名单是否写死?
algorithms: ['HS256']不是null exp是否设置?短有效期是关键防线- secret 是否足够强?HS256 的 secret 至少 32 字节随机
- 敏感信息是否放了 payload?身份证号/手机号/密码都算
- 多服务架构是否升级到 RS256?让其他服务只持公钥
- 是否能在服务端吊销?至少有黑名单或 tokenVersion 机制
实时看 token 内容
粘贴 token,三段着色展开 header / payload / signature,exp / iat 自动换成本地时间,能立刻看到当前 token 还剩多久、到底装了什么——本地解析,token 不上传。