DrillLab
第 96 / 105 道96 / 105 · #359

什么是 JWT

What is JWT

先自己答,再往下看Answer it yourself first

一句话:JSON Web Token —— 一个自带签名的字符串, 服务器不用存它也能验证它没被篡改。

三段结构,用点分隔:header.payload.signature

  • header—— 用什么算法签的
  • payload—— 用户 id、过期时间等业务数据
  • signature—— 对前两段用密钥算出的签名

最重要的一条(必答):前两段只是Base64URL 编码,不是加密——任何人都能解出来看。 所以payload 里绝不能放密码、 身份证号这类敏感信息。 签名保证的是「没被改过」,不是「看不到」

优点:无状态—— 服务器不用存 session, 天然适合多实例和微服务 (任何一台都能独立验证)。

缺点(这半边是重点):

  • 没法主动失效。签出去就有效到过期。 用户改密码、 管理员封号,旧 token 照样能用
  • 体积比 session id 大, 每个请求都要带。
  • 放哪都有风险——localStorage 怕 XSS, cookie 怕 CSRF。

会追问:「怎么让 JWT 提前失效?」—— 这是这题的分水岭:

  • 短过期 + refresh token—— access token 只活 15 分钟, 用一个可撤销的 refresh token 换新的。这是标准做法。
  • 黑名单—— 把要作废的 token id 存 Redis。但这就重新变成有状态了, 等于放弃了 JWT 的主要优点。

安全上还有一个经典坑:验证时必须指定期望的算法, 不能信 header 里写的 —— 否则攻击者把 alg改成 none 就绕过签名了。

In one line: a JSON Web Token is a string that carries its own signature, so the server can verify it has not been tampered with without storing it.

Three parts, separated by dots: header.payload.signature

  • header — which algorithm signed it
  • payload — the data: user id, expiry and so on
  • signature — the first two parts signed with your secret

The one thing you must say: the first two parts are Base64URL encoded, not encrypted anyone can decode and read them. So never put a password or a national id number in the payload. The signature guarantees “unchanged”, not “unreadable”.

The upside: it is stateless — the server stores no session, which suits many instances and microservices, since any one of them can verify it alone.

The downsides — this half is the real question:

  • You cannot revoke it. Once issued it is valid until it expires. User changes their password, an admin bans the account — the old token still works.
  • It is bigger than a session id and rides along on every request.
  • Every place you store it has a risk localStorage is exposed to XSS, a cookie is exposed to CSRF.

Follow-up: “How do you expire a JWT early?” — this is where the question separates people:

  • Short expiry plus a refresh token — the access token lives 15 minutes and you trade a revocable refresh token for a new one. This is the standard answer.
  • A blocklist — keep revoked token ids in Redis. But now you are stateful again, which gives up the main reason you chose JWT.

One classic security trap: when you verify, you must pin the algorithm you expect rather than trust the one in the header — otherwise an attacker sets alg to none and walks past the signature entirely.