Skip to content

你项目用的 JWT,那如何保证安全性?别人拿到你这个 Token 不就可以直接登录你的账号了吗?怎么办? ​

  • 标签:后端、场景题

🏛 业务架构师 ​

JWT 的核心矛盾:无状态的便利 vs 无法作废的风险——Token 被拿走,在过期前它就是"合法的钥匙"。我的回答围绕"降低被窃取概率 + 缩短被盗窗口 + 增加使用门槛"三层。

第一层:防止被窃取(传输与存储)

  • 全站 HTTPS,杜绝链路嗅探——这是底线,没有 HTTPS 谈 Token 安全没有意义
  • 前端存储用内存 + localStorage 谨慎评估(XSS 可读);禁止 URL 传 token(日志、Referer 泄漏的经典途径)
  • payload 里不放敏感信息:JWT 的 payload 只是 Base64 编码,不是加密,等于明文——放过期时间的用户 ID 可以,放手机号就是数据泄漏

第二层:缩短失窃窗口(时效设计)

  • 短 access token(5 分钟~2 小时)+ refresh token(长效,仅用于换发)
  • refresh token 一次性使用 + 轮换(旧 refresh 用过即废 + 检测重放:同一 refresh 被二次使用说明泄漏,作废整个 token 家族)
  • 敏感操作(支付、改密)二次校验:重新验密/生物识别,长效 token 不等于授权通行证

第三层:增加使用门槛与检测

  • 设备指纹/IP 突变检测:Token 带设备 ID,异地使用触发风控(静默换发新 token 使旧的失效、或强制重新登录)
  • 黑名单机制:登出/风控时 token 的 jti 写入 Redis 黑名单,网关校验——恢复"可作废"能力
  • 异常登录提醒("您的账号在异地登录")——最后一道用户侧防线

业务视角收尾:安全投入要匹配账户的资损面:支付类账户全套上(短 token + 二次校验 + 风控),内容社区类适度即可(否则登录频繁过期反而伤留存)。安全设计的目标不是绝对安全,是让攻击成本高于盗号收益。

🏗 系统架构师 ​

这个质疑是对的:JWT 一旦泄露,攻击者在有效期内就是合法用户。我不回避,而是分层防御,把泄露概率与泄露后的爆炸半径都压小。

1. 缩短爆炸半径:短有效期 + 刷新机制 access token 15 分钟,refresh token 7 天且只在大额变更时使用。泄露的 access token 最多活 15 分钟;refresh token 走独立路径(只在认证中心用)并绑定设备指纹,异常即拒绝。

2. 传输与存储防泄露

  • 全站 HTTPS/wss,token 绝不走 URL 参数(会进访问日志与 Referer)
  • Web 端用 HttpOnly + Secure + SameSite Cookie 存 token,防 XSS 窃取(localStorage 可被 XSS 读取,是我的红线)
  • App 端存加密 keystore/keychain

3. JWT 内不放敏感信息 + 防篡改 payload 只是 base64 不是加密,绝不放手机号、权限明细;签名算法固定 RS256/ES256(非对称,资源服务用公钥验签),拒绝 alg: none 攻击与算法混淆。

4. 主动防御:黑名单与版本号

  • 关键操作(改绑手机、支付)二次验证(密码/生物识别),token 被盗也过不了关键闸口
  • 服务端保留踢人能力:token_version 版本号或 Redis 黑名单(详见踢下线方案),异常行为(异地登录、UA 突变)风控触发强制下线
  • 检测同一 token 从两个 IP/设备并发使用 → 疑似泄露,强制刷新

5. 主动失效与轮换 token 轮换:每次 refresh 换新 jti,旧 access 的短窗口是唯一暴露面。

一句话:HTTPS+HttpOnly 防窃取、短有效期+刷新控半径、二次验证+版本号保关键操作,JWT 的无状态优势保留,风险被围堵在 15 分钟窗口内。

💻 全栈开发专家 ​

先直面问题:JWT 被拿走确实能冒用,这是事实。所以我的防御是"让 token 不容易被拿走 + 拿走了也能让它快速失效"。

传输与存储层(防偷)

  • 全站 HTTPS,token 不出现在 URL、不打日志(日志脱敏过滤 Authorization)。
  • 前端放 httpOnly + Secure + SameSite Cookie,防 XSS 窃取;Web Storage 里的 token 是 XSS 活靶子。
  • token 只走 Authorization 头,禁止 Cookie 自动携带到第三方(CSRF 面)。

机制层(限损)

  1. 短有效期 + Refresh Token:access token 5~15 分钟,泄露窗口极小;refresh token 单独存储、仅用于换发新 token,且可服务端撤销。
  2. 服务端可撤销:JWT 的死穴是无法主动失效,我的做法是会话版本号——Redis 存 user:ver:{uid},JWT payload 带 ver,改密码/踢人时 bump 版本,全量旧 token 立即失效(详见踢下线方案)。
  3. 绑定环境特征:payload 里带 device指纹/IP 段/UA 哈希,网关校验严重不符即拒绝并触发风控(异地登录提醒)。
  4. audience/issuer/exp 校验齐全 + jti:jti 记录防重放(配合 Redis 短 TTL 去重),防同一 token 并发滥用。

监控层

异常行为检测:同一 token 两个地域并发使用、请求频率突变 → 自动失效 + 通知用户。

一句话:JWT 不是"签了就不管",我的原则是短命 + 可撤销 + 环境绑定,把静态凭证变成有生命周期的会话。