fix(x402): 有料エンドポイントの応答を no-store にし共有キャッシュへ載せない - #277
Merged
Conversation
本番実測 (2026-07-27) で `/api/paid/*` の応答が Next.js 既定の `cache-control: public, max-age=0, must-revalidate` を返しており、**共有キャッシュ (CDN / プロキシ) への保存が許可**されていた。402 は支払い条件 (payTo / 金額 / forwarder / commitVersion) を、200 は購入者だけが受け取るべき有料コンテンツを含む。 `Vary` に X-PAYMENT が無いため、URL だけを鍵にしたキャッシュが別の買い手へ再配信し得る。 ## 変更 - `handleFirstPartyPaidGet` の出口で `Cache-Control: no-store` を一律に付与。 分岐が 20 以上あり個々の return に付けると新規分岐で漏れるため、境界 1 箇所で保証する (掟13: 何の波及を断つ防御かをコメントで明記)。 - 402 と 200 の双方で no-store を固定するテストを追加。 契機は x402 上流の PR (402 応答へ Cache-Control: no-store を足す議論) と、 主要 Facilitator 15 件の安全規則違反を報告した査読前研究 (arXiv 2026-07-21)。 研究が挙げる他 5 系統 (settle 前の状態再検証 / ガス消耗 / settle 失敗の成功扱い / 支払い後の未配信 / 不明状態の成功扱い) は PR #273 で対応済みのため本 PR では触れない。 ## 検証 typecheck / **full vitest 8036 passed (392 files)** / next build + bundle 予算 全ルート内 / eslint / audit-gate / lockfile-gate PASS。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CNMEwurCJNTrzvr2qypSd
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
本番を実測したところ、
/api/paid/*が Next.js 既定のcache-control: public, max-age=0, must-revalidateを返していました。402 は支払い条件(payTo / 金額 / forwarder / commitVersion)、200 は購入者だけが受け取るべき有料コンテンツを含みます。
VaryにX-PAYMENTが無いため、URL だけを鍵にしたキャッシュが別の買い手へ再配信し得る形でした。変更
handleFirstPartyPaidGetの出口でCache-Control: no-storeを一律に付与します。このハンドラは分岐が 20 以上あり、個々の return に付けると新しい分岐を足したときに漏れるため、境界 1 箇所で保証する形にしました。402 / 200 の双方でno-storeを固定するテストも追加しています。契機と、あえて触っていない範囲
x402 上流の PR(402 応答へ
Cache-Control: no-storeを足す議論)と、主要 Facilitator 15 件の安全規則違反を報告した査読前研究(arXiv・2026-07-21)が契機です。研究が挙げる他の 5 系統は PR #273 で対応済みのため、本 PR では触れていません。
なお本文(v1)とヘッダー(v2)の同一 JSON 強制は行いません。OpenPay は二重互換設計のため、経済条件の等価性で担保する方が適切です。
検証
next build+ bundle 予算 — 全ルート内🤖 Generated with Claude Code
https://claude.ai/code/session_015CNMEwurCJNTrzvr2qypSd