HMACを計算、またはWebhookから届いた署名をチェック
このHMAC生成ツールは、HMAC-SHA256、HMAC-SHA1、HMAC-SHA384、HMAC-SHA512で秘密鍵を使ってメッセージに署名し、署名を小文字hex、大文字hex、Base64、Base64urlで同時に表示します。キーとメッセージはそれぞれプレーンテキスト、hex、Base64で入力できるため、生のバイナリシークレットにもパスワードにも対応します。受け取った署名 — GitHubの<code>sha256=…</code>、Stripeの<code>t=…,v1=…</code>ヘッダー、またはただのBase64 — を貼り付ければ、一致するかどうかがわかります。計算にはブラウザのWeb Crypto APIを使用し、キーとメッセージがページの外に出ることはありません。
HMACの生成・検証方法
- 1ハッシュ関数を選びます。ほとんどのAPIとWebhookはSHA-256を使っています。
- 2秘密鍵を入力または貼り付け、表記形式(テキスト、hex、Base64)を選びます。ランダムキーを使うと、適切な長さの新しいシークレットを作成できます。
- 3メッセージを貼り付けます。Webhookの場合は、届いたままの生のリクエストボディを1バイトも変えずに使います。
- 4必要なエンコーディングで署名をコピーします。署名を確認するには期待される署名に貼り付けます。
sha256=などのプレフィックスは自動で認識され、無視されます。
HMACとは?
HMAC(hash-based message authentication code、RFC 2104)は、メッセージと秘密鍵から計算される短い値です。キーを知っている人は同じ値を計算でき、メッセージが途中で改ざんされていないこと、そしてキーを持つ人が作成したことの2点を同時に確認できます。キーがなければ、攻撃者は新しいメッセージに対して有効なHMACを偽造することも、メッセージを変更した後にHMACを合わせることもできません。
HMACは単にキーとメッセージをつなげてハッシュしたものではありません。キーを内側と外側のパッドに混ぜ込み、2回ハッシュします:H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ message))。この構造により、H(key ‖ message)として単体で使うと伸長攻撃(length-extension attack)に弱いSHA-256やSHA-512でも安全に使えます。
Webhook署名の検証
多くのWebhookプロバイダーは、各リクエストのボディのHMACで署名し、その結果をヘッダーに入れます。検証するには、署名用シークレットで生のボディのHMACを計算し、ヘッダーの値と比較します。最もよくある間違いは、届いたバイト列ではなく再シリアライズしたJSONオブジェクトをハッシュしてしまうことです。キーの順序が違ったりスペースが1つ欠けたりするだけで、署名はまったく別物になります。
ボディ以外も署名に含めるプロバイダーもあります。Stripeはtimestamp.body(ヘッダーのtの値、ドット、ペイロード)を、Slackはv0:timestamp:bodyを署名します。その文字列を正確に組み立ててここのメッセージにし、ヘッダー全体を検証欄に貼り付けてください。v1=またはv0=の値が自動で取り出されます。
- GitHub
- <code>X-Hub-Signature-256: sha256=<hex></code>、Webhookシークレットをテキストとして使ったボディのHMAC-SHA256。
- Stripe
- <code>Stripe-Signature: t=…,v1=<hex></code>、<code>t.body</code>のHMAC-SHA256。
- Shopify
- <code>X-Shopify-Hmac-Sha256: <Base64></code>、ボディのHMAC-SHA256。
- Slack
- <code>X-Slack-Signature: v0=<hex></code>、<code>v0:timestamp:body</code>のHMAC-SHA256。
テキスト、hex、Base64のキー
キーはバイト列であり、その表記方法が重要です。テキストのabc123は6バイトですが、hexのabc123はまったく異なる3バイトです。多くのサービスはシークレットをhexやBase64の文字列で発行しますが、その文字列自体をテキストキーとして使うことを想定しています(GitHubもStripeもそうです)。一方、AWS方式の署名チェーンやShopifyのアプリプロキシなどはデコードしたバイトを使います。署名が一致しないときは、まずキーのエンコーディングを切り替えてみてください。
新しいキーには、ハッシュ出力と同じ長さ以上のランダムバイトを使います。HMAC-SHA256なら32バイト、HMAC-SHA512なら64バイトです。それより長くしても意味はありません。ハッシュのブロックサイズを超えるキーは、最初にハッシュされて短くなります。
定数時間比較
サーバーで署名をチェックするときは、Node.jsのcrypto.timingSafeEqual、Pythonのhmac.compare_digest、PHPのhash_equalsなどの定数時間関数で比較してください。通常の文字列比較は最初に異なる文字で止まるため、かかった時間から偽造した署名がどこまで正しかったかが漏れる可能性があります。このページも同じ定数時間のパターンを使っているので、コードはチェックだけでなく参考実装にもなります。
キーなしでファイルやテキストの通常のチェックサムが欲しいだけなら、ハッシュ値計算ツールを使ってください。トークンの署名には、JWT シークレットジェネレーターで適切なサイズのHS256キーを作成できます。
よくある質問
- ハッシュとHMACの違いは何ですか?
- SHA-256などのハッシュはデータだけで決まるため、誰でも再計算できます。HMACは秘密鍵にも依存するため、キーを持つ人しか生成も検証もできません。そのためHMACは完全性だけでなく、真正性の証明にもなります。
- HMACがAPIのものと一致しないのはなぜですか?
- ほぼ必ず入力が異なっています。メッセージが生のボディとバイト単位で一致していない(再シリアライズしたJSON、末尾の改行、改行コードの違い)、サービスはhexやBase64のバイトを想定しているのにキーをテキストとして読んでいる(またはその逆)、あるいはプロバイダーがボディだけでなくタイムスタンプとボディを署名している、といったケースです。
- どのHMACアルゴリズムを使えばよいですか?
- HMAC-SHA256が標準的な選択で、ほぼすべてのAPIが使っています。HMAC-SHA512も同様に問題なく、64ビットサーバーではより高速です。HMAC-SHA1はSHA-1の衝突があってもHMACとしては依然安全ですが、プロトコルで必要な場合にだけ使ってください。
- HMAC-SHA1は破られていますか?
- いいえ。SHA-1の衝突を使ってもキーなしでHMAC-SHA1を偽造することはできず、HMAC-SHA1に対する実用的な攻撃は知られていません。新しい設計には非推奨ですが、既存のHMAC-SHA1署名を検証するのは安全です。
- ここでHMAC-MD5を計算できますか?
- いいえ。このページが使っているブラウザのWeb Crypto APIはMD5を実装していません。HMAC-MD5は古いプロトコルに残っているだけなので、新しいものにはHMAC-SHA256を使ってください。
- HMACキーの長さはどれくらいにすべきですか?
- 少なくともハッシュ出力と同じ長さです。HMAC-SHA256なら32バイト、SHA-384なら48バイト、SHA-512なら64バイトのランダム値です。ランダムキーボタンは、ブラウザの安全な乱数生成器でちょうどその長さを生成します。
- 空のキーは使えますか?
- HMACでは許可されており結果も明確に定義されるため、ツールは結果を表示します。ただし、空のキーや短いキーでは安全性はまったくありません。誰でも同じ署名を計算できてしまいます。
- 秘密鍵はどこかに送信されますか?
- いいえ。HMACはこのページ上でブラウザのWeb Crypto APIによって計算されます。入力した内容がアップロードや保存されることはありません。