ハッシュ・ID・乱数
Webhook署名が一致しない。HMACの条件を確認したい
使うツール
受信したWebhookのJSONは正しく見えるのに、署名チェックだけが失敗する。そんな場面では、JSONの内容が同じという確認だけでは足りません。HMACが計算するのは、鍵とメッセージのバイト列の組合せです。JSONのキー順や空白を整えた後の文字列は、送信元が署名した本文とは別かもしれません。ここでは公開してよい練習用の鍵を使い、どこをそろえるべきかを一つずつ調べます。
既知の鍵と本文で、計算経路を確かめる
HMAC計算で方式をSHA-256、出力を16進数にし、鍵へkey、本文へThe quick brown fox jumps over the lazy dogを入力します。前後に空白や改行を足しません。次の値になれば、この条件では方式と入力がそろっています。これは公開された練習用文字列であり、本番の秘密鍵として使うものではありません。まず小さな既知の例を通すと、実データだけで試すより切り分けがしやすくなります。
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8この値は本文だけのSHA-256とは異なります。鍵を使わないハッシュ計算へ同じ本文を貼り付けても、HMACの確認にはなりません。また、鍵と本文を単純に連結してSHA-256を計算する方式でもありません。受信側の仕様がHMAC-SHA-256なら、同じ方式を選ぶ必要があります。SHA-384やSHA-512が使われている場合も、推測せず提供元の仕様で確認します。
JSONを整形しただけでも、別の署名になる
次の二つのJSONは、値として読めば同じです。しかし、コロンの後の空白、改行、キーの順序が違えば、HMACへ渡るバイト列も違います。署名検証前にJSON.parseしてからJSON.stringifyしたり、整形ツールを通したりすると、送信元の本文を再現できないことがあります。受信した生の本文を使う仕様なら、そのバイト列を保持して検証する必要があります。
{"amount":100,"currency":"JPY"}
{ "amount": 100, "currency": "JPY" }本文末尾のLFとCRLFも区別されます。HTTPライブラリ、ファイル保存、エディター、コピー操作のどこで変わったかを追うときは、見た目の比較に加えてバイト数や16進表示が役立ちます。ただし、常に文字列へ戻せばよいわけではありません。バイナリー本文なら文字コード変換で内容が変わり得るため、このツールではファイル入力の生バイトと、UTF-8の文字列入力を区別します。
『同じ鍵』は、同じ文字列とは限らない
鍵として6b6579と書かれている場合、それが六文字のテキストなのか、16進数で表した三バイトなのかを確認します。後者を復元するとkeyですが、このツールの鍵欄へ6b6579と入力しても自動で16進復元しません。鍵欄はUTF-8文字列として扱います。Base64表記の鍵についても同様です。見た目の文字が同じというだけで、仕様どおりの鍵バイトを渡せたとは限りません。
任意のバイナリー鍵をこの画面で無理に扱うため、文字化けした文字列へ変換しないでください。正確なバイトを渡せるローカル実装や提供元のSDKで確認する必要があります。鍵を変えて一致するまで試すより、鍵の発行方法、保存形式、読み込み時の復元処理をそろえる方が原因へ近づけます。画面の鍵バイト数も、余分な改行や復元漏れに気付く補助になります。
署名対象は本文だけとは限らない
サービスによっては時刻、HTTPメソッド、パスなどを決められた順番で連結してHMACへ渡します。その場合、本文だけを入力しても一致しません。区切り文字、改行、URLのエンコード、時刻の表記まで、提供元が定める署名対象文字列を確認します。このツールは汎用HMAC計算であり、任意のWebhook仕様を自動判定して署名対象を組み立てる機能ではありません。
結果も16進数、Base64、Base64urlで見た目が変わります。この画面の出力は16進数またはBase64なので、Base64urlの値と比較する場合は表記の違いを整理します。ヘッダーにsha256=などの接頭辞が付く仕様もありますが、それが署名そのものの一部とは限りません。どの部分を比較するかを仕様で確認し、都合よく文字を削って合わせないようにします。
一致しても、受信処理の安全性は別に確認する
同じ鍵とメッセージで同じ結果が出ることを確認できても、そのリクエストが新しいか、再送されたものかまでは分かりません。時刻や一意なIDを使った再送対策、比較処理の実装、鍵の管理などは受信側の責務です。この計算画面だけでWebhook認証を完成させたとは考えないでください。調査では方式、鍵の表記、署名対象バイト、出力表記を一項目ずつ固定すると、変更の影響を追えます。
本番の鍵をチャットやチケットへ貼るのではなく、再現用の練習鍵と架空の本文を用意すると調査を共有しやすくなります。入力を外部へ送信しないツールでも、画面共有やクリップボードの取り扱いは別です。もし秘密鍵を不適切な場所へ公開してしまったら、画面を消すだけで解決したとは扱わず、提供元や組織の鍵更新手順へ進みます。まず例のkeyで、計算の条件をそろえる練習をしてください。
受信したJSONを、署名前に整形し直していないか
受信側でJSONを読み取り、オブジェクトからもう一度JSON文字列を作ってHMACを計算すると、送信側の生の本文と一致しない場合があります。キーの順序、空白、改行、エスケープの表し方が変わるためです。データとして同じ内容かを調べるJSON構造比較と、署名対象のbyte列が同じかを調べる作業は別です。仕様が生の本文を対象としているなら、その本文を検証用に確保する必要があります。比較しやすくするための整形が、比較対象そのものを変える点に注意します。
切り分けは一度に全部を変えず、公開された既知の鍵と短い本文で始めます。その組で合わなければ、アルゴリズムや出力形式、鍵の読み方を調べます。そこで一致して実データだけが違うなら、実本文のbyte列や署名対象の組み立て方へ進めます。鍵の内容をログへ出して確かめる方法は避け、長さやエンコード方式など秘密を露出しない情報から調べます。この画面の鍵入力はUTF-8の文字列であり、16進表記を貼ればそのbyte列へ自動復元されるわけではありません。
最終的に一致しても、過去に受け取った正しいリクエストを再送する攻撃への対策までは確認していません。時刻、nonce、イベントIDなどを使う仕様なら、その検証や重複処理防止も受信アプリ側で必要になります。HMACは本文の暗号化ではなく、共有鍵を使った認証用の計算です。結果を一致させる調査と、安全に一度だけ処理する仕組みを分けて設計すると、署名が合うことだけを処理全体の合格条件にせずに済みます。