
JWT(JSON Web Token)因为自包含、无状态、跨服务易传递,成为前后端分离和微服务场景的主流鉴权方案。用户登录后拿到 Token,后续请求带上即可,服务端不用存会话,天然适合分布式。但很多团队对 JWT 的特性理解不深,落地后出现一堆安全问题:Token 泄露后无法让它失效、密钥写死在代码里、Payload 里放敏感信息、登出和刷新逻辑混乱,甚至直接把 JWT 当成"绝对安全"的认证凭证。
JWT 本身只是一种"经过签名的自包含凭证",它的安全取决于签发、传输、存储、校验和刷新整条链路。本文从常见安全坑点出发,讲清楚 JWT 该怎么签发、校验、刷新、登出,以及密钥和跨域怎么管。
一、JWT 落地高频安全坑点
1. 敏感信息放进 Payload,泄露后直接暴露
JWT 的 Payload 只是 Base64 编码,不是加密,任何人都能解码看到内容。如果把手机号、身份证、权限明细等敏感信息写进 Payload,Token 一旦泄露,这些信息就直接暴露。更危险的是,Payload 内容会随每个请求传输,增加泄露面。
2. 密钥硬编码、强度不足,Token 可被伪造
签名密钥写死在代码或配置里、用弱密钥、或多环境共用同一密钥,一旦泄露或被破解,攻击者就能伪造任意用户的 Token。密钥还会随代码进入版本库,传播面失控。
3. 不校验或校验不完整,签名被绕过
只解析 Payload 不验签、把 alg 设为 none 绕过校验、不校验过期时间和签发方,都会让伪造的 Token 蒙混过关。校验环节缺一项,等于整套鉴权形同虚设。
4. 登出即失效做不到,Token 过期前一直可用
JWT 是无状态的,签发后在过期前一直有效。用户主动登出、改密码、被踢下线后,旧 Token 在过期前仍能访问接口,这是 JWT 最被诟病、也是最常被忽视的坑。
二、Token 签发与校验的正确做法

1. Payload 只放必要、非敏感的标识
Payload 只放用户 ID、过期时间、签发方等鉴权必需信息,不放手机号、邮箱、权限明细等敏感内容;用户详情、权限列表在请求时从服务端按用户 ID 查询,而不是塞进 Token。
2. 使用强密钥并按环境隔离
使用足够长度的随机密钥,通过配置中心或密钥管理服务注入,不写死在代码和仓库里;开发、测试、生产使用不同密钥,密钥定期轮换;禁止使用 alg=none 或弱算法。
3. 完整校验签名与声明
校验时必须验证签名算法、签名、过期时间(exp)、签发方(iss)、受众(aud)等声明,任何一项不通过都拒绝请求。下面是一段典型的签发与校验示例:
// 签发:登录成功后生成短期 access token String token = Jwts.builder() .setSubject(userId) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000)) .signWith(secretKey, SignatureAlgorithm.HS256) .compact(); // 校验:解析时自动验签并校验过期时间 Claims claims = Jwts.parserBuilder() .setSigningKey(secretKey) .build() .parseClaimsJws(token) .getBody(); String uid = claims.getSubject();
三、Access Token 与 Refresh Token 双令牌机制

1. 短期 Access Token + 长期 Refresh Token
Access Token 有效期设短(如几十分钟),用于接口鉴权;Refresh Token 有效期长,只在刷新时使用。Access Token 即使泄露,可用时间也很短,降低风险面。
2. Refresh Token 需服务端记录
Refresh Token 在服务端(如 Redis)留存并与用户、设备绑定,支持主动失效;用户登出或改密码时,把对应 Refresh Token 标记为失效,刷新请求直接拒绝。
public String refresh(String refreshToken) {
// 1. 校验 refreshToken 签名与有效期
String uid = parseAndVerify(refreshToken);
// 2. 查服务端:该 refreshToken 是否仍有效、是否被吊销
if (!refreshTokenStore.isValid(uid, refreshToken)) {
throw new AuthException("refresh token 已失效,请重新登录");
}
// 3. 重新签发新的 access token
return issueAccessToken(uid);
}3. 登出与吊销

登出时把 Refresh Token 从服务端删除或标记为失效;对安全要求高的场景,可把即将过期的 Access Token 也加入短期黑名单(如 Redis,过期时间与 Token 一致),实现"登出即失效",而不是干等它自然过期。
四、传输、存储与跨域安全
1. 全程 HTTPS,防止 Token 被中间人截获
Token 只在 HTTPS 下传输,HTTP 明文传输会让 Token 在链路上被嗅探。同时设置合理的过期时间,缩短泄露后的可用窗口。
2. 前端存储权衡
存 localStorage 方便但易受 XSS 窃取;存 HttpOnly Cookie 可防 XSS 读取,但要配合 CSRF 防护。按业务安全等级选择存储方式,并在前端做好输入过滤,降低 XSS 风险。
3. 接口限流与异常监控
对登录、刷新接口做限流,防止暴力破解和 Token 爆破;对验签失败、过期、刷新异常等情况记录日志并监控,发现异常调用模式及时告警。
五、总结
JWT 的安全不来自"用了它",而来自整条链路的工程细节。核心可以归纳为:Payload 只放非敏感标识,不存敏感数据;密钥强、按环境隔离、不进代码仓库;签发后完整校验签名与各项声明;用短期 Access Token 加服务端记录的 Refresh Token 做双令牌,配合黑名单实现登出即失效;全程 HTTPS,前端存储按安全等级选择,并对登录刷新接口做限流监控。JWT 不是银弹,把这些坑填上,无状态鉴权才能真正安全可用。
在线
电话
微信
需求
TOP