令牌里装了什么
JWT 由点号分成三段。前两段是 Base64url 编码的 JSON,谁都能读;第三段是签名。
- 头部 — 放签名算法(
alg)和类型(typ)。会轮换密钥的服务还会带一个kid,指明这次用的是哪把密钥。 - 载荷 — 放各种声明。
sub是用户标识,iss是签发方,aud是这枚令牌的预期接收方,exp、iat、nbf则是时间。 - 签名 — 用密钥对前两段签出来的值。
规范规定时间类声明是以秒为单位的整数。有些令牌把毫秒填了进去,在这里就会显示成几千年之后,那是签发一方的缺陷。
解码不等于验证
在这里能读出内容,并不说明这枚令牌是真的。载荷没有上锁,谁都能改;签名对不对,只有握着密钥的一方才知道。
所以服务端必须在每个请求上验证签名,而且验证时不能听信头部的 alg。用于验证的算法要在服务端固定下来,遇到 alg 是 none 或与预期不符时直接拒绝。照着头部走的实现,正是让无签名令牌蒙混过关的经典漏洞。
别把秘密放进载荷
只要拿到令牌,哪怕只是打开浏览器的开发者工具,载荷就一览无余。里面若有身份证号、内部管理备注或支付信息,那就等于已经公开了。
适合放进去的,是那些被持有者看到也无妨的值:用户 ID、角色名、过期时间。其余的留在服务端,用到时再查。
粘贴别人的令牌之前
这个工具不会把令牌发到任何地方。但没过期的令牌本身就是一张通行证:贴进聊天室或工单系统,看到的人当场就能用。万一泄漏了,别等它自己过期,直接把那个会话作废。