← すべてのツール
私たちのメモ

CyberChefX-Device-Signature を手で検証する

webhook 署名が一致しないとき、まず切り分けるべきはどちら側が間違っているか——あなたか、私たちか。CyberChef を使えば UnifyPort と完全に同じ署名アルゴリズムを、ハンドラが見ているのと同じ入力で、ブラウザ上から 30 秒ほどで再現できます。

UnifyPort は何に署名しているのか

署名シークレットが設定されたすべての配信には、三つのヘッダがつきます:

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 の間の 1 バイトは ASCII のドット(.)であり、改行ではない。
  • raw_body とは私たちが送った生バイト——あなた側で JSON パース、空白除去、Unicode 正規化が行われるのもの。
  • hex 出力は小文字。大文字の digest と比較すると false-negative になる。

CyberChef レシピ

CyberChef でレシピペインに次の二つのオペレーションを順に置きます:

  1. 1. HMAC——Hashing functionSHA256 に設定。署名シークレットを Key に貼り、TypeUTF8
  2. 2. To Hex——Delimiter は空、Bytes per line0。これで区切りのない小文字 hex 文字列が出力され、ヘッダに一致します。

Input ペインに貼るのはちょうど <timestamp>.<raw_body>——例えば:

1716800000.{"id":"evt_demo","type":"message.received",...}

Output ペインの値は配信の X-Device-Signature と一致するはずです。一致しないなら、バグは三つのうちどれか——シークレットが違う、body が途中で変えられた、timestamp を間違ったヘッダから読んだ。

この手動検証が本当に効くとき

  • 署名シークレットをローテートした直後。DNS や古いデプロイを疑う前に、新しいシークレットがハンドラに届いているか確認できる。
  • JSON ライブラリをアップグレードした直後。パーサが検証側に渡す前に body を吐き直すことがある——気づかないうちに署名が合わなくなる。
  • 同僚が「私の環境では動く」と言ったとき。同じレシピと同じ入力を二人で走らせ、digest が違う方が間違ったシークレットを持っている。

ウェブページにシークレットを貼ることについて

CyberChef は完全にクライアントサイドの静的バンドル——あなたのブラウザ内だけで動き、公式ホスト版ではシークレットがマシンを離れることはありません。とはいえブラウザ拡張や共有セッションが心配なら、CyberChef をローカルで動かす(リポジトリを clone して index.html を開く)か、DevToys——完全オフラインなデスクトップ版——を使ってください。本番の署名シークレット運用には、CyberChef の出力を目で見るのではなく、コードで constant-time 比較すべきです。

手で検証した後

同等のロジックをハンドラに落とし込みましょう。主要言語の標準ライブラリには既に primitive があります:Node の crypto.createHmac、Python の hmac.new、Go の hmac.New。比較は必ず constant-time な関数(timingSafeEqualhmac.compare_digesthmac.Equal)で——絶対に == を使わない。