Webhook HMAC検証
定義
ShopifyがWebhookをHTTPSで配信するとき、リクエストにはHMAC-SHA256の署名が付く。受け取る側は同じ計算を再現し、値が一致したときだけ本文を信用する。
- 署名の場所: X-Shopify-Hmac-SHA256 ヘッダー。Base64でエンコードされた値が入る
- 計算に使うもの: 鍵はアプリのクライアントシークレット、メッセージは生のリクエストボディ
- 判定: 自分で計算した値とヘッダーの値を突き合わせ、一致しなければ本文を読まずに拒否する
- 適用範囲: HTTPS配信のみ。Google Cloud Pub/SubとAmazon EventBridgeへの配信では、経路自体がクラウド側で閉じているため不要
同じ仕組みは、Shopify Flowのアクションエンドポイントなど、Shopifyから自社サーバーへPOSTが届く他の場面でも使われる。
背景
Webhookの受け口はインターネットに公開されたURLで、アドレスさえ知られれば誰でもPOSTできる。検証を省いたエンドポイントは、外部から任意の注文作成イベントや返金イベントを流し込める入口になる。ECでは在庫の引き当て、ポイント付与、基幹システムへの連携、顧客へのメール送信といった処理がWebhookを起点に動くため、偽のイベントがそのまま実害に変わる。
実装でつまずきやすいのは、署名の計算対象が生のボディである点。多くのWebフレームワークは受信したJSONを自動でパースするため、パース済みのオブジェクトを文字列に戻して計算すると、空白やキーの順序が変わって署名が一致しない。ボディを解釈する前のバイト列を確保しておく必要がある。突き合わせにも、単純な文字列比較ではなくタイミング攻撃に強い比較関数を使うのが定石。クライアントシークレットを更新したときは、新しい値で署名が生成されるまで最大1時間かかる点も運用上の注意になる。
検証が保証するのは「Shopifyから来たこと」だけで、「一度しか来ないこと」は保証しない。再送や重複配信に備えて、X-Shopify-Webhook-Id で重複を弾くか、処理そのものを冪等にしておく。
Flagshipでの関わり
自社で公開しているShopifyアプリと、クライアント案件の連携基盤の双方で、Webhook受信の標準実装として組み込んでいる。アプリのボイラープレートに検証処理を最初から含めることで、案件ごとに書き直して抜けが出る状態を避けている。エンタープライズ案件では配信方式そのものをPub/SubやEventBridgeに寄せる設計も採るため、その場合はHMAC検証の代わりに、配信経路とクラウド側の権限設計で正当性を担保する。重複配信と取りこぼしはこれとは別の問題として扱い、冪等な処理や、定期ポーリングによるリコンサイルジョブと組み合わせて設計している。