JWT 解析
拆三段并格式化,iat/exp 转可读时间,可填密钥验 HMAC 签名。
JWT 是用点号连起来的三段 Base64URL:header(算法与类型)、payload(声明)、signature(签名)。Base64URL 是可逆编码而不是加密,所以任何一段内容都能直接读出来——本工具正是这么做的:拆段、严格解码、给每个声明配一条中文注解。
验签只对 HS256/HS384/HS512 有效:填对称密钥后,浏览器内用 WebCrypto 重算 HMAC 并与第三段逐字节比对,给出「签名匹配」或「签名不匹配」。RS/ES/PS 系列是非对称算法,验签需要 PEM 公钥,本页不模拟结果,请直接交给本站的 RSA 工具。解码过程中发现的算法伪造、令牌过期、外部取密钥地址一类风险都会以横幅列出——这才是这类解码器的主要价值:让你看见攻击面。所有内容都留在浏览器里,不上传、不联网、也不写 cookie。
JWT 解析怎么用
- 哪些声明有注解:RFC 7519 的七个注册声明(iss、sub、aud、exp、nbf、iat、jti)按规范解释,OIDC 与 IANA 注册表里常见的公共声明(email、name、preferred_username、scope、role 等)单列,其余一律标成「私有声明」,不替应用瞎猜含义。两段还原出的缩进 JSON 收在各自卡片里那条「原始 JSON」折叠中(默认收起,常驻的是解读表)。
- 时间声明与签名段:exp、iat、nbf、auth_time 这四个时间声明按 Unix 秒定义,工具会同时给出本地时间、UTC 时间和「已过期 12 分钟 / 还有 3 小时」的相对说法,数值写成毫秒(有效期被放大 1000 倍)这类常见错误也会被点名。签名段与验签那一卡并排列出:签名输入串(前两段用点号连接)、第三段原文、解码后的字节数与十六进制。
- 粘贴即解:把 eyJ 开头的 Token 贴进顶部那条全宽输入框(带 Bearer 前缀或换行折行都能识别),框下方立刻把同一串按 header · payload · signature 三段原样染出来,每段带上真实字符数;点任意一段,焦点和滚动会移到对应的卡(Header(头部参数)/Payload(声明)/签名段),Header 与 Payload 的解读表每个声明带一行中文说明,重新缩进的 JSON 在那张卡的「原始 JSON」折叠里。凑不齐三段就不染色,只说明差在哪。
- 本地验 HMAC:在 Token 下方那行「本地验签」里填服务端那把对称密钥,页面用 WebCrypto 重算 HMAC 并比对第三段;密钥短于摘要长度时会额外提醒弱密钥爆破风险。
- 看告警定位问题:Token 卡下方的红/灰横幅说明当前令牌的风险:alg=none、签名段非空却写 none、exp 已过期、nbf 未到、缺 typ、header 与 payload 的 alg 不一致、jku/x5u 与 kid 相关风险等。
常见问题
为什么不验签也能看到内容?那 JWT 还算安全吗?
因为签名保护的是「完整性与来源」,不是「机密性」。payload 只是 Base64URL 编码的 JSON,任何人拿到字符串都能还原成原文——Base64URL 里没有密钥这种概念,它跟加密毫无关系。签名只能证明「这段话没被改过、是持密钥者签发的」,不能阻止阅读。所以规矩是:JWT 里不放密码、身份证、手机号、内部权限矩阵这类敏感内容,只放标识符和短期限的声明;需要机密性时用 JWE(加密套一层)或干脆走服务端会话,把数据留在数据库里。
服务器应该怎么正确验签?
一条都不能少:一,算法白名单硬编码在服务端配置里,绝不按令牌 header.alg 动态挑验签实现——这是 alg:none 与 RS256→HS256 混淆(把公开的公钥当 HMAC 密钥,CVE-2016-10555、CVE-2026-22817)的共同成因,none 必须显式拒绝;二,用成熟库(jose、PyJWT、jjwt 等)而不是手写,调用时把 algorithms 参数写死;三,比对签名用常数时间比较(Node 的 crypto.timingSafeEqual、Java 的 MessageDigest.isEqual),逐字节短路的比较会泄露时间信息;四,除了验签还要校验 iss、aud、exp、nbf,并给 iat 留出时钟容差;五,HMAC 密钥不短于摘要长度(HS256 至少 32 字节随机值),别用 secret、changeme、项目名这类字典词,否则 hashcat -m 16500 离线跑一遍就人人能签发;六,kid 只能查白名单,不能拼进文件路径或 SQL,jku/x5u 默认不取。
exp 换算出来比本地时间差 8 小时,是不是解析错了?
不是,exp 本身就是与时区无关的:它是从 1970-01-01T00:00:00Z 起算的秒数(一个绝对时刻),不存在「几点」的问题。差 8 小时几乎总是转换环节出的错:把本地时间字符串(比如 "2026-10-05 12:00:00")直接 new Date() 或写进数据库,让它按本地时区解释了一遍;或者用 LocalDateTime / DateTimeFormatter 这类不带时区的类型去承载它;或者数据库连接时区与应用时区不一致(MySQL 的 serverTimezone、JDBC 的 connectionTimeZone);或者把毫秒当秒除了一次。正确做法是内部一律按 UTC 存储与计算(Instant / epoch 秒),只在展示给用户时才转本地时区——本工具两列都给:「本地」按你浏览器时区显示、「UTC」按 Z 显示,两者指同一个瞬间,相对说法(还有多久过期)不受时区影响。
对应功能编号 #32无需安装,手机端同样可用按 Ctrl + K 换工具