JavaScriptmicroCMSNext.jsReactSaaS / FaaS

Next.js App RouterでmicroCMS Webhookの発行元を検証する

この記事では、Webhookを利用してCMSと外部サービスを連携する方法について説明されています。Webhook機能は最近のWebサービスやCMSで標準で提供されており、サービス同士の連携ワークフローを自動化することができます。microCMSでは、コンテンツごとにWebhookを設定することができ、APIで検証するためにシークレットキーを登録することもできます。また、Next.jsを使用してWebhookからのリクエストを検証する方法も説明されています。Webhookを利用してシステムとの連携を安全に行うために、シークレットの利用が重要です。

広告ここから
広告ここまで

この記事は、「CMS(WordPressやヘッドレスCMS) Advent Calendar 2023」12日目の記事です。

WebhookでCMSと外部サービスを連携する

最近のWebサービスやCMSには、Webhook機能が標準で提供されています。この機能を使うことで、例えば「記事の更新を反映させるために、SSGのビルドワークフローを開始する」ことや、「Algolia / Elasticsearch / OpensearchまたはベクトルDBなどに、検索用のインデックスを登録・更新する」ことといった、サービス同士の連携ワークフローを自動化できます。

microCMSでは、コンテンツ(API)ごとにWebhookを設定する

microCMSでは、コンテンツ(API)ごとにWebhookを設定できます。そのため、「このタイプのコンテンツは連携させたいが、他のタイプについてはその必要がない」などの判断が行えます。

Webhookからのリクエストであることを、APIで検証する

Webhookを利用したシステム連携では、「Webhookからのリクエスト以外のAPI呼び出しを、どのように無害化するか」が重要な要件としてあがります。これは、「Webhookから送信されるAPIリクエストと同じようなPOSTリクエストを、外部の第三者が直接送信してくる」などの攻撃を受けた際に、連携するサービスが意図しない動作を行わないようにするために行います。

microCMSでは、Webhookごとにシークレットキーを登録できます。この設定はダッシュボードから行いましょう。

設定したシークレットは、microCMSから送信されるWebhookのリクエストヘッダーに含まれます。

microCMSから送信される検証用シークレットを、Next.jsで取得する

ダッシュボードで設定したシークレットを利用して、「microCMSから送信されたリクエスト」であることを検証する処理を作りましょう。今回はHeadless CMSのフロントエンドで利用されることの多い、Next.jsを利用します。

POSTリクエストを受け付けるPOST関数の中で、x-microcms-signatureヘッダーを取得しましょう。

export async function POST(request: NextRequest) {
  return NextResponse.json({
    message: 'demo',
    header: request.headers.get('x-microcms-signature'),
  })
}

上のサンプルでは、取得したシークレットをそのままレスポンスで返します。下のcURLコマンドを実行すると、headerに送信したヘッダー情報が含まれたJSONがかえってきます。

% curl -XPOST http://localhost:3000/api/webhook -H "X-MICROCMS-Signature:whsec_demo"

このサンプルでは、次のようなレスポンスが取得できます。

{
  "message":"demo",
  "header":"whsec_demo"
}

取得できたシークレットを利用して、検証処理を実装しましょう。

環境変数から検証用のコードを取得し、リクエストを検証する

ヘッダーからシークレットを取得する処理を実装しましたので、あとは検証用のコードを作ります。まずはmicroCMSで登録したシークレットキーを、Next.jsの環境変数に登録しましょう。

MICROCMS_WEBHOOK_SECRET=whsec_demo

環境変数に設定した値と、リクエストヘッダーで送信されてきた値が同じであることを、if文で検証します。一致しないか、どちらかの値が存在しなかった場合は、HTTP 401でエラーを返しましょう。

export async function POST(request: NextRequest) {
  const microCMSWebhookSecret = process.env.MICROCMS_WEBHOOK_SECRET
  if (microCMSWebhookSecret && microCMSWebhookSecret !== request.headers.get('x-microcms-signature')) {
    return NextResponse.json(
      {
        message: 'Unauthorized',
      },
      {
        status: 401,
      },
    )
  }
  return NextResponse.json({
    message: 'ok',
  })
}

cURLで検証する

最後に不正なAPIよびだしをブロックできているか試しましょう。下のcURLでは、不正なシークレットをヘッダーに設定して送信しているため、レスポンスがエラーになっています。

% curl -XPOST http://localhost:3000/api/webhook -H "X-MICROCMS-Signature:INVALID_CODE"
{"message":"Bad request."}

正しいシークレットをヘッダーに設定すると、レスポンスが返ってきました。

% curl -XPOST http://localhost:3000/api/webhook -H "X-MICROCMS-Signature:whsec_demo"
{"message":"ok"}

まとめ

このように、比較的シンプルな設定と実装で、Webhook APIを保護することができます。Webhookを利用してシステムとmicroCMSを連携させる場合には、シークレットを利用して安全にAPI連携を行えるようにしましょう。

参考

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts