2026-08-07 02:49:49 分类:科技
我一直觉得 JWT 是个很分裂的设计——它优雅得像数学公式,却又粗暴得让你想砸键盘。你知道那种感觉吗?当你看完 RFC 7519,心想“哦,这不就是 base64 加个签名嘛”,结果线上事故后才发现,自己连那串字符的长度都没关注过。对,说的就是我。
上周,朋友公司又因为 JWT 密钥泄露,用户会话被接管。电话里他声音都变了:“哥,不是说无状态吗,怎么撤都撤不回?” 唉,这是第几个了?第四个,还是第五个?每次都是同样的坑,换个花样摔。于是我想,干脆把 JWT 的底裤扒光,连带着这些年淌过的血泪,一起倒出来。
Sign me, seal me: 那串点号连接的到底是什么?
JWT 最常见的全称是 JSON Web Token,说白了就是个经过签名的 JSON。你看那串 eyJhbGciOiJIUzI1NiJ9… 的东西,其实用点号分成三块:头部、载荷、签名。头部告诉你算法,载荷里塞点用户 id、过期时间,签名用密钥一算,完事。有人把它比做“装在透明信封里的信”——谁都能看见内容,但改不了,因为信封上的蜡封印(签名)会破坏。这个类比差了点意思,更准确说,它像你给一个 json 文件打了个数字签名,然后 base64 编码了。对,就是这么简单。但简单背后藏着一个精妙之处:它不依赖服务端存储。你的令牌就是你的身份。每次请求,客户端带着它,服务端掏出密钥,重新算一遍签名,对上了就放行。省去了查数据库或 Redis 的步骤。这在微服务间调用时特别爽——服务 A 签发,服务 B 不用问 A,直接本地验签就能确认身份。但代价呢?你很快就看到了。
JWT 签名验证原理步骤图解
没有银弹:10000 并发下的数据幻象与现实耳光
没有银弹:10000 并发下的数据幻象与现实耳光
很多人一上来就吹 JWT 性能吊打 Session。说实话,我也曾是其中之一。直到我们做了次压测,脸都肿了。场景是这样:两个简单的 API,一个用 JWT (RS256, 2048 位密钥),另一个用 Session + Redis,只存一个 user_id。10000 并发持续 30 秒,我眼珠子差点掉出来——JWT 的 QPS 竟然比 Redis 低约 15%。怎么回事?不是省了网络调用吗?后来才整明白,非对称签名(RS256)的 CPU 开销巨大,每次请求都要做一次签名验证,而 Redis 只是内存读取,网络耗时在万兆网下根本不算什么。但当我把算法换成 HS256(对称密钥,仅 sha256 一次),QPS 反超 Redis 近 22%。因为没了网络往返和反序列化开销。所以你看,这就是工程——没有放之四海而皆准的结论。你选哪种算法,某种程度上是在用 CPU 换内存或延迟。还有,载荷大小也很要命。如果你把用户角色、权限列表全塞进 JWT,一个令牌就膨胀到 4KB 多。在 HTTP 头里传来传去,带宽和时延不跟你客气。我们测过,同样 10000 并发,3KB 大小的 JWT 对比 200 字节,平均响应时间增加了 18ms。听着不多?在高频交易里这就是灾难。
那些让你在深夜里 debug 到撞墙的陷阱
好,说三个必定会有人踩的坑。没踩过算我输。
第一坑:忘了吗?Payload 是透明的! 多少次了,在 jwt.io 上随手一解码,就看到里面躺着手机号、甚至密码。颤抖吧,凡人们。Base64 不是加密,是编码。你的 payload 如同穿着皇帝的新装,任何人拿到令牌都能读出内容。所以,绝对不能放敏感数据。要么整个 JWE(JSON Web Encryption)加密,但这会带来性能损耗;要么只放不敏感的东西,比如用户 id 和权限标记。记死了。
第二坑:过期与撤销,无状态的诅咒。 JWT 一旦签发,在有效期前就是“不死之身”。用户登出、封禁?不好意思,只要令牌没到期,它照样能进门。怎么办?常见的补救是维护一个很小的黑名单(比如只记录那些被强制登出的 jti),放在 Redis 里,验证时先查一下。这又有点回到有状态了,但没办法,现实需求就这样恶心。另一个策略是用极短有效期(如 5 分钟),配合 refresh token。短令牌泄露危害小,refresh token 可以后端控制撤销。这种“双令牌轮换”算是目前最靠谱的实践。
第三坑:签名算法,别被 “none” 开了后门。 很多库支持 “alg”: “none” 来表示无签名,直接放行。如果你的验证代码不小心忽略了算法白名单,攻击者发一个 none 算法的令牌,你就是皇帝,什么都是真。永远强制指定算法列表,如 [‘HS256’, ‘RS256’],拒绝 none。还有弱密钥问题,对称算法别用 “secret”,至少来个 256 位随机字符串。密钥文件权限设好,泄露了就不是玩笑,是整个认证体系的崩塌。
JWT 令牌撤销黑名单架构设计
余味:在废墟上欣赏一点工程美学
尽管坑多,我依然欣赏 JWT 背后的思想。那是种简洁的暴力——把信任塞进一个自包含的令牌,让服务回归无状态。它促成了真正弹性的架构,服务器可以随时重启、扩缩,而不用同步共享 session 存储。这种无依赖的认证,像极了 Unix 哲学中的小工具组合。设计者当初大概就想:为什么每次请求都要翻一下数据库?何不把用户信息打个包,签名后随身携带?于是有了这个精巧的三段式结构。它让分布式系统的认证模块变得“无粘性”,任意节点都能独立处理请求。但美归美,落地时的每一行代码都要敬畏:你签下名字的那一刻,就承担了与之相应的安全责任。
唠叨这么多,无非是想告诉你:JWT 不是花架子,但它是把双刃剑。拿好它,别伤着自己。
免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:JWT 深度拆解:流着泪写完的避坑手册
文章链接:https://m.lfdjt.com/info_23_7807.html