Skip to content

fix(worker): constant-time webhook signature verification #229

Description

@liplus-lin-lay

目的

verifyGitHubSignatureworker/src/signature.ts)の署名比較が expected === signature非定数時間比較で、最初の不一致文字で early-exit する=期待署名がレスポンスタイミングから漏れるタイミングサイドチャネル(trust boundary の弱点)。姉妹リポ github-rag-mcp で対応済み(#171 / #167 修正)の定数時間化を webhook-mcp にも移植する。

方針(rag-mcp #171 と同一パターン)

  • hex 文字列の === 比較をやめる。sha256= prefix 検証 → ^[0-9a-fA-F]{64}$(32byte)を事前検証して malformed を fail-fast → 生バイト(Uint8Array(32))に復元 → crypto.subtle.verify("HMAC", key, sigBytes, body)内部定数時間比較
  • importKey の usage を ["sign"]["verify"] に。
  • 機能的契約は不変: 正しい署名→true / それ以外(改竄・別secret・malformed)→false

テスト

  • 既存 signature.test.ts を rag-mcp webhook.test.ts のケースに揃える。GitHub 公式ドキュメント「Validating webhook deliveries」の公開ベクトル(secret="It's a Secret to Everybody" / body="Hello, World!" / 既知署名)を独立 oracle に。
  • 非hex ケース(sha256= + "z".repeat(64) → false)を追加し、新しい hex 検証を pin。
  • harness は webhook-mcp 既存様式(node:test + node:assert/stricttsx --test)を維持。rag-mcp の vitest 構文は移植しない。

影響スコープ

  • 署名検証の内部実装+テストのみ。機能的観測変化なし(timing 特性のみ改善、入出力契約は同一)→ patch

target files

  • worker/src/signature.ts(実装差し替え)
  • worker/test/signature.test.ts(ケース更新)

関連

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreadybody converged for implementation

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions