PG官网

400-920-5594
173-6014-8050
首页 > 资讯中心 > 技术分享
JWT 鉴权落地避坑复盘:Token 被盗用、密钥硬编码、无法登出、刷新混乱的接口安全生产级方案
2026-09-29 33 技术分享

PG官网

  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 签发与校验的正确做法

PG官网

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 双令牌机制

PG官网

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. 登出与吊销

PG官网

  登出时把 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 不是银弹,把这些坑填上,无状态鉴权才能真正安全可用。

推荐文章查看更多》

网站地图