FixVibe

// コード / スポットライト

Webhook署名検証

Webhookハンドラーが署名を検証しなければ、誰でもイベントを偽造できます。

概要

Webhook signature verification is one of the most consistently-skipped steps in integration code, and the reason is structural: the integration works fine without it. The webhook arrives, the body parses, the handler runs, the test passes. Verification is the step you only notice when an attacker posts a forged event to your endpoint. Stripe, GitHub, Clerk, Resend, Linear, Slack, Vercel, and every other service worth integrating with sets a signature header — `Stripe-Signature`, `X-Hub-Signature-256`, `svix-id`, etc. — and explicitly tells you to verify before trusting the payload. The instructions are in the documentation. The skipping is in the codebase.

仕組み

Each provider computes an HMAC over the raw request body (using a secret you configure on their side), serializes the result into a header, and sends both. Your handler is supposed to: read the raw body (not the parsed body — parsing changes whitespace and breaks the HMAC), recompute the HMAC using your shared secret, compare with the header using a timing-safe equality function, then trust the body. Skip the check and you accept any payload from any caller — Stripe's webhook URL is not authenticated by IP, secret token in URL, or any other mechanism; the signature is the only authentication. The mistakes cluster in three shapes: never adding the verification call (the handler trusts everything), parsing the body before verifying (the HMAC fails because the parsed-and-reserialized body has different whitespace), and using non-timing-safe comparison (`===` against the signature is technically right but timing-leaks the secret bit-by-bit).

バリエーション

No signature check at all

Handler parses and trusts every incoming POST. Most common shape; trivially exploitable by anyone who knows the URL.

Verify-after-parse

Handler parses body to JSON, then computes HMAC over the JSON.stringify version. Whitespace differs from the original; HMAC fails. Verification 'works' for legit events because both sides round-trip the same way, but is broken for production-grade attackers.

Non-timing-safe comparison

`if (signature === expectedSignature)` instead of `crypto.timingSafeEqual(...)`. Leaks one bit per request through timing analysis. Less common in practice but a genuine vulnerability.

Replay without timestamp check

Even with HMAC verification, accepting old timestamps lets an attacker replay captured events. Stripe's signature includes a timestamp; rejecting events older than 5 minutes defeats replay.

被害範囲

Forged events. Stripe webhook fakery: an attacker posts a fake `payment_intent.succeeded` event to your `/api/stripe/webhook` endpoint, your handler marks the order as paid, you ship goods you weren't paid for. GitHub webhook fakery: fake `release.published` event triggers your CI to deploy attacker-controlled artifacts. Clerk webhook fakery: fake `user.created` event seeds a malicious user into your database with admin role. The pattern is identical across providers — without signature verification, the webhook endpoint is an unauthenticated mutation API.

// what fixvibe checks

What FixVibe checks

FixVibe repo scans look for high-confidence security patterns and dependency risk in source context. Reports identify the affected area and recommended fix. For check-specific questions about exact detection heuristics, active payload details, or source-code rule patterns, contact support@fixvibe.app.

鉄壁の防御

Always verify signatures before parsing or trusting any body field. Use the official SDK helper when available — `stripe.webhooks.constructEvent(rawBody, sig, secret)` for Stripe, GitHub's documented HMAC SHA-256 over rawBody compared with `crypto.timingSafeEqual`, `svix.verify(rawBody, headers)` for Svix-shaped providers (Resend, Clerk, Linear). Critical: read the raw body before parsing — `req.text()` in Next.js, `bodyParser.raw()` in Express, `express.raw({ type: '*/*' })` middleware, or framework-specific raw-body access. Reject requests without signatures, even in test environments; sloppiness in test becomes sloppiness in prod. Validate the timestamp included in the signature (Stripe's tolerance is 5 minutes by default) so old captured events can't be replayed. Store webhook event IDs after processing and refuse re-processing the same ID — handles legitimate retries without enabling deliberate replay. As a final layer, scope the webhook secret per-provider per-environment so a leak is contained.

要点

Signature verification is the difference between a webhook endpoint that's part of a trusted integration and one that's a public mutation API. The verification call is one line. Skipping it is the kind of bug you find in a postmortem rather than a code review.

// あなたのアプリで実行してみてください

FixVibe が見守る間も、安心して出荷を続けられます。

FixVibe は攻撃者と同じ視点で、あなたのアプリの公開面を徹底的にテストします —— エージェント不要、インストール不要、クレジットカード不要。新しい脆弱性パターンを継続的に研究し、実用的なチェックと Cursor、Claude、Copilot 向けの貼り付け可能な修正に変換します。

ソースコード
52
このカテゴリで実行されるテスト
モジュール
14
専用の ソースコード チェック
1スキャンごと
384+
全カテゴリ合計のテスト
  • 無料 —— カード不要、インストール不要、Slack 通知不要
  • URL を貼り付けるだけ —— クロール、検査、レポートはお任せ
  • 重大度別に分類、シグナルだけに重複排除
  • 最新の AI 修正プロンプトを Cursor、Claude、Copilot にそのまま貼り付け
無料スキャンを実行

// 最新チェック · 実用的な修正 · 安心してリリース

Webhook署名検証 — 脆弱性スポットライト | FixVibe · FixVibe