杂记 › 技术笔记 › 13格算法表与7道验签闸门:JWT 工具页验签侧的分支比解码侧更窄,逐算法真签真验矩阵

13格算法表与7道验签闸门:JWT 工具页验签侧的分支比解码侧更窄,逐算法真签真验矩阵

同一枚 JWT 粘进解码页,读得出内容却验不过签名:ALGS 的 13 格只写了三类字段、12 算法 × 4 入口的真签真验矩阵、签名段字节跟密钥不跟哈希、七道闸门里六道走在读密钥之前,逐算法量过。

同一枚 JWT 读得出内容,却验不过签名

一枚 RS256 令牌贴进解码页,头部与载荷照样解码,点「验证签名」却回「还没有输入密钥」。把模板整段 script 丢进 node:vm 跑一遍才明白:这页把「读」和「验」做成两套判定,验签侧窄到只有 13 个算法名进得了门,前六道闸门还不看你填的密钥。

被测的是 JWT 解析 那页,768 行、38463 字节,账目在 ALGS(L199–213)、pemToDer(L604)、doVerify(L648)三处;令牌与密钥全用 demo- 前缀自签。

13 格里只写了三类字段

Object.keys 数出 13 个键,即图 1 左列。hashByte 只在 HS 三档(32/48/64),salt 只在 PS 三档(32/48/64),curve 只在 ES 三档(P-256、P-384、P-521),余下 10 格三类字段全无,none 只有 family。

最容易上当的是 ES512:键里 512、曲线却是 P-521,差 9;坐标每段 66 字节,签名 132 是 2×66 而非 2×64。

13 个算法键 → family → 面板开关 HS ×3 · hashByte 32/48/64 hmac HMAC 框 RS ×3 · 三类字段全无 rsa 公钥框 PS ×3 · salt 32/48/64 pss 公钥框 EC ×3 · curve P-521 ec 公钥框 none · 只有 family 一格 none 三元素全隐藏

图 1:字段决定家族,家族决定面板显隐。

签名段字节跟密钥跟哈希,不跟算法名

  • HS 三档 32、48、64 字节,跟 hash,与那三格 hashByte 逐一对上。
  • RS256@2048 与 RS384@2048 同为 256,RS512@4096 才 512,PS 三档同账。
  • ES256 是 64、ES384 是 96、ES512 是 132,跟曲线。

换成 base64url 字符数就是图 2 末行十二档,与 ceil(bytes/3)*4 减补位在 12 行逐行相等。

字节数(柱高)与字符数(末行) 32 48 64 64 96 132 256 256 512 HS256 HS384 HS512 ES256 ES384 ES512 RS256 RS384 RS512 43 64 86 86 128 176 342 342 683

图 2:两根同高柱子来自 2048 位的 RS256 与 RS384。

12 算法 × 4 入口,只有两种结果

每行令牌的 kid 写成 demo-key-1、载荷 lvl 写成 3,HS 密钥 demo-shared-key-2026-b22,非对称现生成 RSA-2048/4096 与三条 P 曲线的 PEM。四个入口只有两种结果:正确密钥与导出成 JWK 各 12/12 通过;lvl 从 3 改成 4 而签名段原样、或换一把同参数错钥,都是 12/12 不匹配。

密钥进门先看首字符

importKey 先 trim,再看首字符是不是 {:能解析走 jwk,否则 hmac 落 raw、其余落 spki。同一段密钥写成 raw 与写成 JWK,重算签名逐字节一致,32 字节、64 字符 hex。坑是 {"a":1}:解析得动、进 jwk 支抛 DataError,message 无中文,回落成「粘贴的密钥内容不完整,或与头部声明的算法不匹配」。

PEM 的三条拒绝加一次救回

BEGIN/END 不匹配报「没有识别到 PEM 的 BEGIN/END 标记」,裸 base64 也落这条;label 不是 PUBLIC KEY 就回显识别到的名字(CERTIFICATE、RSA PUBLIC KEY 各一条);BEGIN 与 END 不对称时反向引用失配,仍落第一条。body 先去空白、再把 - 换 +、_ 换 / 才进 atob,失败报「Base64 无法还原(长度 N)」,N 是去空白后的字符数。一次救回:RSA-2048 demo 公钥的 SPKI DER 294 字节编成 392 字符,19 枚 + 与 / 全换成 base64url 写法后两次输出逐字节一致;另一把 15 枚。字符表差别见 Base64。

七道闸门,六道走在读密钥之前

闸门触发回显
L650没有令牌只 toast「先粘贴一个令牌」
L6515 段 JWE「无法验签」
L654alg 为 none「没有签名可验」
L658家族不在四类「不在本机可验证的范围内」
L663没有 WebCrypto浏览器口径,未实测
L667缺第 3 段「缺少签名段」
L675密钥框空白「还没有输入密钥」

七道都在密钥框留空下跑过,除最后一道外无一回显密钥文案,前六道在 L672 读 keyText 前返回。第四道喂了 6 个输入:HS224、ES256K、EdDSA、hs256、A128GCM 与头部不带 alg,全落这一条,查表大小写敏感。

两条分支失败时回吐的东西不一样

HMAC 是自己重算再比:sign 得到 expect 交给 equalBytes(先比 length,再定长 XOR-OR 折叠),失败时两段各印前 8 字节,恒为 16 个十六进制字符加一枚省略号。RS、PS、EC 走 verify,只回布尔值,「签名 N 字节」只在成功文案里;255 字节的 RS256 与 63 字节的 ES256 截短签名在 Node 侧返回 false,进「签名不匹配」而不报错。

salt 也不反映在长度上:PS256 的 saltLength 被写死成 32,同一把 RSA-PSS-2048 下 salt=20 签发的签名仍是 256 字节 342 字符,却验不过,面板也不提 salt。

口径补一句:除表中标注外全部为纯 Node 实测;DOM 像素、渲染定时器触发次数、非对称库对截短签名是否抛错,本批未开浏览器,记未实测。

三个面板开关各自听 family 的

jwt-hs-box 只在 hmac 开,jwt-pk-box 只在 rsa/pss/ec 开,按钮取两者的或。八种输入:没有 alg、未知串 XYZALG、none 三种三元素全隐藏;HS256 只开 HMAC 框;RS256、PS384、ES512 只开公钥框;塞一段长度除以 4 余 1 的坏签名,开关不动,只有那一行中段从「N 字节」换成「无法解码」。

常见问题

Q:同一个 JWT 粘进去,为什么这页读得出内容却验不过签名?

两套判定:解码只要求段能切开、字节能还原,验签要先过闸门——alg 得在 13 格里、家族在四类内、真有第 3 段。三段结构与 exp 的读法见站内那篇 旧文。

Q:签名段是 256 字节,就一定是 RS256 吗?

不一定,RS 与 PS 在 2048 位下都是 256 字节 342 字符;跟哈希的只有 HS 三档,跟曲线的只有 ES 三档。

Q:密钥填了,为什么还说没有输入密钥?

要么填错了框——显隐由 alg 决定,落在四类外或没有 alg 时连按钮一起隐藏;要么那一格只有一串空格。

📎 相关文章

8 个元素算得出 40320 条却只列 5000 行:排列计算器的两道互不相干的上限、重复元素按 3! 计数与 n≤20 的过程断点 2026-11-12 投放链接的装配顺序与大小写折叠:UTM 生成器六态标注、两道硬上限与五栏各用一把尺实测 2026-11-12 拖到 4 和拖到 8,屏幕上都是 43890 个块:马赛克预览与导出的两套块网格、三档会崩与 6px 误触阈值 2026-11-10 位图进 SVG 只换了个盒子:232 字节容器常数、一个从不生效的「base64 嵌入」勾选,与四档缩放下纹丝不动的 142064 个字符 2026-11-10 转完悄悄少了 271 个字符:Markdown 转 HTML 的洞协议、64 轮回填与 20 条提示上限 2026-11-10