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連携を行えるようにしましょう。