← 所有工具
用 CyberChef 手动校验
我们的笔记
用 CyberChef 手动校验 X-Device-Signature
webhook 签名对不上时,你首先要判断的是哪一侧错了——你的还是我们的。CyberChef 能让你在浏览器里跑 UnifyPort 完全一样的签名算法,用 handler 看到的同一组输入,三十秒内出结果。
UnifyPort 到底在签什么
每次投递只要配置了签名密钥,就会带三个 header:
X-Device-Delivery-Id: d_01J2K…
X-Device-Timestamp: 1716800000
X-Device-Signature: 9f8c…
签名按以下方式计算:
X-Device-Signature = hex( HMAC-SHA256( secret, timestamp + "." + raw_body ) )
调试前贴几条在屏幕边:
- timestamp 和 body 中间的那个字节是 ASCII 点号(
.),不是换行。 raw_body指我们发过去的原始字节——在你这边做任何 JSON 解析、去空白、unicode 归一化之前。- hex 输出是小写。如果跟大写 digest 比对,会假阴性。
CyberChef recipe
在 CyberChef 里按顺序把两个操作丢进 recipe 面板:
- 1. HMAC——把 Hashing function 设成
SHA256。把你的签名密钥贴进 Key,Type 选UTF8。 - 2. To Hex——Delimiter 留空,Bytes per line 设成
0。这样能得到没有空格的小写 hex 字符串,跟 header 对得上。
在 Input 面板里粘贴的内容必须正好是 <timestamp>.<raw_body>——比如:
1716800000.{"id":"evt_demo","type":"message.received",...}
Output 面板出来的应该跟那条投递里的 X-Device-Signature 一致。如果不一致,bug 锁定在三处之一:用了不同的 secret、body 在路上被改过、或者你读的是错的 timestamp header。
这种手动校验真正派上用场的时刻
- 轮换签名密钥之后。在你怀疑 DNS 或部署没刷新之前,先确认新密钥确实到了 handler。
- 升级 JSON 库之后。有些解析器在交给验证逻辑前重新输出过 body——这种事很容易漏看,直到签名突然对不上。
- 队友说"我这里能跑"的时候。两个人各跑同一个 recipe、同一组输入;digest 不一样的那个就是拿了错的 secret。
把密钥贴进网页这件事
CyberChef 是纯静态的客户端 bundle——完全在你浏览器里跑,官方托管版本里 secret 不会离开你的机器。话虽如此,如果你担心浏览器扩展或共享会话,可以本地跑 CyberChef(clone 仓库后打开 index.html)或者用 DevToys——完全离线的桌面端等价物。生产环境的签名密钥轮换,要走代码做 constant-time 比对,而不是肉眼看 CyberChef 输出。
手动验过之后
把等价逻辑搬进你的 handler。大多数语言标准库里就有原语:Node 的 crypto.createHmac、Python 的 hmac.new、Go 的 hmac.New。比对一定要用 constant-time 函数(timingSafeEqual、hmac.compare_digest、hmac.Equal)——绝对不要用 ==。