Skip to content

fix(worker): constant-time signature verification (patch)#230

Merged
liplus-lin-lay merged 1 commit into
mainfrom
229-fixworker-constant-time-webhook-signature-verification
Jun 21, 2026
Merged

fix(worker): constant-time signature verification (patch)#230
liplus-lin-lay merged 1 commit into
mainfrom
229-fixworker-constant-time-webhook-signature-verification

Conversation

@liplus-lin-lay

Copy link
Copy Markdown
Member

Closes #229

概要

verifyGitHubSignature(worker/src/signature.ts)の署名比較を、非定数時間の expected === signature から crypto.subtle.verify(内部で HMAC を再計算し定数時間比較)に切り替えた。sha256= prefix と厳密な 64 hex 文字(32 byte)形状を crypto 到達前に検証して malformed を fail-fast し、生 32 byte digest に復元してから verify する。

背景

=== 比較は最初の不一致文字で early-exit するため、期待署名がレスポンスタイミングから漏れる timing side-channel(webhook trust boundary の弱点)だった。姉妹リポ github-rag-mcp で対応済み(#171 / #167 修正)の定数時間化パターンを webhook-mcp に移植した。

影響スコープ

patch。署名検証の内部実装+テストのみ。機能契約は不変で、入出力の観測変化なし(timing 特性のみ改善)。正しい署名→true / それ以外(改竄・別 secret・malformed)→false

変更ファイル

  • worker/src/signature.ts(実装差し替え+top コメント更新)
  • worker/test/signature.test.ts(GitHub 公式公開ベクトルを primary oracle にケース更新)

確認

  • npm test(worker/): tsx --test 54 pass / 0 fail(うち signature 7 件)+ vitest 25 pass / 0 fail = 計 79 pass、全パス。
  • npx tsc --noEmit: 新規型エラーなし。既存の src/agent.ts(31,32 行、MCP SDK 由来)2 件は baseline のまま。
  • GitHub 公開ベクトル(secret="It's a Secret to Everybody" / body="Hello, World!")を独立 oracle と一致確認済み。

Switch verifyGitHubSignature from a non-constant-time `expected === signature`
hex compare to crypto.subtle.verify, which recomputes the HMAC and compares it
in constant time internally. The `===` path early-exited on the first mismatched
character, leaking the expected signature through response timing — a timing
side-channel at the webhook trust boundary. Validate the `sha256=` prefix and a
strict 64-hex-char shape before touching crypto so malformed input fails fast
and uniformly, then reconstruct the raw 32-byte digest and verify it.

姉妹リポ github-rag-mcp で対応済み(#171 / #167)の定数時間化を webhook-mcp に
移植した。機能契約は不変で、正しい署名のみ true、改竄・別 secret・malformed は
すべて false を返す。

Tests use GitHub's own published example vector ("Validating webhook
deliveries") as an independent oracle plus a node:crypto createHmac oracle.
The timing property itself is not unit-observable; the tests pin the functional
contract the constant-time implementation preserves.

Closes #229
@liplus-lin-lay liplus-lin-lay linked an issue Jun 21, 2026 that may be closed by this pull request
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
github-webhook-mcp 1fd39a5 Jun 21 2026, 05:22 AM

@liplus-lin-lay liplus-lin-lay left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI self-review (auto mode)

実差分・テスト・CI を確認(subagent 報告の裏取り込み)。github-rag-mcp #171#167 修正)の定数時間化を忠実に移植。

コード(signature.ts

  • expected === signature(非定数時間、early-exit で期待署名が timing から漏れる)を撤去。
  • 署名を sha256= prefix 検証 → ^[0-9a-fA-F]{64}$(32byte)で fail-fast → 生バイト復元 → crypto.subtle.verify("HMAC", key, sigBytes, body)内部定数時間比較
  • importKey usage を ["sign]"["verify"] に変更。
  • doc コメントを #227 + #229 で更新、timing side-channel の背景を明記。
  • → rag-mcp src/webhook.ts のパターンと一致。機能的契約は不変(正しい署名→true / 他→false)。

テスト(signature.test.ts

  • GitHub 公式「Validating webhook deliveries」の公開ベクトル(secret="It's a Secret to Everybody" / body="Hello, World!" / 既知署名)を primary oracle に。被験コードに依存しない独立検証。
  • 7ケース: 公開ベクトル正常 / 本文改竄 / 別secret / prefix無し / 空 / 長さ違い / 非hex(z×64) → 期待通り。
  • 既存 node:test + node:assert/strict 様式維持。

分類

  • patch 妥当。入出力契約は同一、timing 特性のみ改善=ユーザー/システム観測可能な機能変化なし。

CI

  • CI / test / Workers Builds 3本 pass。ローカル npm test = tsx 54 + vitest 25 = 79本 green、tsc は baseline と同一(新規エラーなし)。

→ approve 相当。squash merge へ。

@liplus-lin-lay liplus-lin-lay merged commit 2085f03 into main Jun 21, 2026
3 checks passed
@liplus-lin-lay liplus-lin-lay deleted the 229-fixworker-constant-time-webhook-signature-verification branch June 21, 2026 05:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(worker): constant-time webhook signature verification

1 participant