<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Web 安全 on 逍遥笔记</title><link>https://blog.7qiang.com/categories/web-%E5%AE%89%E5%85%A8/</link><description>Recent content in Web 安全 on 逍遥笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>逍遥笔记</copyright><lastBuildDate>Sat, 01 Aug 2026 20:00:00 +0800</lastBuildDate><atom:link href="https://blog.7qiang.com/categories/web-%E5%AE%89%E5%85%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>提链 — ChatGPT 跨区支付链接提取的完整技术拆解</title><link>https://blog.7qiang.com/posts/chatgpt-paylink-extraction-technical-guide/</link><pubDate>Sat, 01 Aug 2026 20:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/chatgpt-paylink-extraction-technical-guide/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post 提链 — ChatGPT 跨区支付链接提取的完整技术拆解" /&gt;&lt;section class="xiaoyao-contact-card" aria-label="联系逍遥"&gt;
 &lt;img class="xiaoyao-contact-card__qr" src="https://blog.7qiang.com/contact-qr.png" width="690" height="690" loading="lazy" decoding="async" alt="逍遥微信二维码"&gt;
 &lt;div class="xiaoyao-contact-card__content"&gt;
 &lt;h3 class="xiaoyao-contact-card__title"&gt;联系逍遥&lt;/h3&gt;
 &lt;p class="xiaoyao-contact-card__description"&gt;扫码添加微信，或点击下方按钮复制联系方式。&lt;/p&gt;
 &lt;div class="xiaoyao-contact-buttons" data-contact-buttons&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--wechat" type="button" data-copy-contact="plus6566" data-copy-label="微信号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;微信&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;plus6566&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--qq" type="button" data-copy-contact="826215906" data-copy-label="QQ 号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;QQ&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;826215906&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;span class="xiaoyao-contact-feedback" role="status" aria-live="polite"&gt;&lt;/span&gt;
&lt;/div&gt;

 &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;进微信群请联系博主，各位觉得文章对你有帮助的话可否打赏一些呀~&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;⚠️ 免责声明&lt;/strong&gt;：本文仅供安全研究与技术讨论。文中不提供可直接复用的攻击工具或完整利用脚本。本文目的是帮助开发者理解 Stripe 跨区支付的工作原理，以及为什么某些支付方式在不同区域可见性不同。提链工具不篡改金额、不注入优惠码，用户以正常价格通过本地支付方式完成订阅。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;“提链&amp;quot;这个词，最近在各种 ChatGPT 合租群、代充群里频繁出现。&lt;/p&gt;
&lt;p&gt;什么意思呢？简单来说：&lt;strong&gt;把 ChatGPT 的信用卡结账页面，转换成一个本地支付方式（iDEAL / UPI / PIX / Kakao Pay / GCash…）的跳转链接。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你可能会问——OpenAI 不是只接受信用卡吗？&lt;/p&gt;
&lt;p&gt;准确地说，&lt;strong&gt;OpenAI 的前端只展示信用卡表单&lt;/strong&gt;。但后端用的是 Stripe，而 Stripe 在全球支持几十种本地支付方式。这些支付方式对应的国家、货币、支付类型都不同，OpenAI 在结账页面上做了筛选，只让你看到&amp;quot;信用卡 / 借记卡&amp;quot;一个选项。&lt;/p&gt;
&lt;p&gt;但 Stripe 的能力是在的。只要你能在创建 Checkout Session 时告诉 Stripe “我要用荷兰 iDEAL 支付”——Stripe 就会老老实实返回一个 iDEAL 的跳转链接。&lt;/p&gt;
&lt;p&gt;提链，就是&lt;strong&gt;从 Stripe 的 Checkout Session 里把这个跳转链接提出来&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;上一篇文章我们拆了 &lt;a class="link" href="https://blog.7qiang.com/posts/chatgpt-plus-0php-cross-region-pricing-exploit-2026/" target="_blank" rel="noopener"
 &gt;0 PHP 白嫖 ChatGPT Plus&lt;/a&gt; 的跨区定价混淆攻击。那个是利用区域信号碎片化 + 工具注入参数让金额变成 0——纯粹的漏洞利用，现在大概率已经被修了。&lt;/p&gt;
&lt;p&gt;而提链不同。&lt;strong&gt;提链是正常的商业行为&lt;/strong&gt;——用户以当地正常价格、通过当地正常的支付方式付款。只不过 OpenAI 的 UI 不展示这些选项，你得自己绕过前端的限制，直接和 Stripe 对话。&lt;/p&gt;
&lt;p&gt;今天把它从协议层完整拆开。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一为什么需要提链信用卡的困境"&gt;一、为什么需要提链——信用卡的困境
&lt;/h2&gt;&lt;p&gt;全球 80 亿人，有信用卡的不到 20 亿。&lt;/p&gt;
&lt;p&gt;印度人用 UPI，巴西人用 PIX，荷兰人用 iDEAL，韩国人用 Kakao Pay，越南人用 MoMo。这些不是什么小众支付方式——它们在各自国家的渗透率往往超过 70%。&lt;/p&gt;
&lt;p&gt;但 OpenAI 的结账页面只给你一个 Stripe Elements 信用卡表单：卡号、有效期、CVC。没有信用卡？不好意思。&lt;/p&gt;
&lt;p&gt;讽刺的是，Stripe 本身是支持这些本地支付方式的。OpenAI 创建 Checkout Session 时，就是通过 &lt;code&gt;billing_details.country&lt;/code&gt; 和 &lt;code&gt;billing_details.currency&lt;/code&gt; 来决定哪些支付方式可用。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;国家&lt;/th&gt;
 &lt;th&gt;货币&lt;/th&gt;
 &lt;th&gt;可用支付方式&lt;/th&gt;
 &lt;th&gt;月费&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;??🇱 荷兰&lt;/td&gt;
 &lt;td&gt;EUR&lt;/td&gt;
 &lt;td&gt;iDEAL&lt;/td&gt;
 &lt;td&gt;€20&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🇮🇳 印度&lt;/td&gt;
 &lt;td&gt;INR&lt;/td&gt;
 &lt;td&gt;UPI&lt;/td&gt;
 &lt;td&gt;₹1,950&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🇧🇷 巴西&lt;/td&gt;
 &lt;td&gt;BRL&lt;/td&gt;
 &lt;td&gt;PIX&lt;/td&gt;
 &lt;td&gt;R$99.90&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;??🇭 瑞士&lt;/td&gt;
 &lt;td&gt;CHF&lt;/td&gt;
 &lt;td&gt;TWINT&lt;/td&gt;
 &lt;td&gt;CHF 20&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🇰🇷 韩国&lt;/td&gt;
 &lt;td&gt;KRW&lt;/td&gt;
 &lt;td&gt;Kakao Pay&lt;/td&gt;
 &lt;td&gt;₩26,400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🇵🇱 波兰&lt;/td&gt;
 &lt;td&gt;PLN&lt;/td&gt;
 &lt;td&gt;BLIK&lt;/td&gt;
 &lt;td&gt;zł79.99&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🇻🇳 越南&lt;/td&gt;
 &lt;td&gt;VND&lt;/td&gt;
 &lt;td&gt;MoMo&lt;/td&gt;
 &lt;td&gt;₫460,000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;??🇭 菲律宾&lt;/td&gt;
 &lt;td&gt;PHP&lt;/td&gt;
 &lt;td&gt;GCash&lt;/td&gt;
 &lt;td&gt;₱990&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些价格不是我编的——它们真实存在于 Stripe 的 Checkout Session 响应里。OpenAI 按照区域设置了不同的定价，Stripe 负责处理。只是 OpenAI 的前端选择性地隐藏了这些支付方式。&lt;/p&gt;
&lt;p&gt;提链工具要做的，就是&lt;strong&gt;绕过前端的限制，以目标国家/货币创建 Checkout Session，然后从 Stripe 的 confirm 响应中提取第三方支付的跳转链接&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二提链的技术原理四步拆解"&gt;二、提链的技术原理——四步拆解
&lt;/h2&gt;&lt;h3 id="step-1获取-access-token"&gt;Step 1：获取 Access Token
&lt;/h3&gt;&lt;p&gt;登录 chatgpt.com，在浏览器中打开：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://chatgpt.com/api/auth/session
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;返回一个 JSON：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;user-xxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;accessToken&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;accessToken&lt;/code&gt; 是一个标准 JWT，有效期通常 5~10 分钟。它是后续所有 API 调用的认证凭据。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;提链工具同时也支持直接粘贴 &lt;code&gt;__Secure-next-auth.session-token&lt;/code&gt; cookie——这个 cookie 可以用来换取新的 access token。但最简单的方式还是直接复制上面的 JSON。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="step-2创建-checkout-session"&gt;Step 2：创建 Checkout Session
&lt;/h3&gt;&lt;p&gt;用 Access Token 调用 OpenAI 的 checkout API：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://chatgpt.com/backend-api/payments/checkout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Authorization: Bearer eyJ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;entry_point&amp;#34;: &amp;#34;all_plans_pricing_modal&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;plan_name&amp;#34;: &amp;#34;chatgptplusplan&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;billing_details&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;country&amp;#34;: &amp;#34;NL&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;currency&amp;#34;: &amp;#34;EUR&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt; &amp;#34;checkout_ui_mode&amp;#34;: &amp;#34;custom&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键参数是 &lt;code&gt;billing_details&lt;/code&gt; 里的 &lt;code&gt;country&lt;/code&gt; 和 &lt;code&gt;currency&lt;/code&gt;。这两个字段决定了 Stripe 在初始化支付页面时会提供哪些支付方式。传 &lt;code&gt;NL&lt;/code&gt; + &lt;code&gt;EUR&lt;/code&gt;，Stripe 就会在 &lt;code&gt;payment_method_types&lt;/code&gt; 里包含 &lt;code&gt;ideal&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;响应：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checkout_session_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;oaics_xxxxxxxxxxxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;processor_entity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;openai_llc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;publishable_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pk_live_xxxxxxxxxxxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;payment_method_types&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;card&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ideal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;oaics_&lt;/code&gt; 前缀是 OpenAI 定制的 Stripe Checkout Session ID 格式。&lt;/p&gt;
&lt;h3 id="step-3stripe-协议流程"&gt;Step 3：Stripe 协议流程
&lt;/h3&gt;&lt;p&gt;拿到 Checkout Session ID 后，需要完成一系列 Stripe API 调用。这是提链的核心技术含量所在——不是简单地 POST 一个接口就完事了。&lt;/p&gt;
&lt;p&gt;完整的协议流程有 12 步：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 1. Session Refresh │ (用 cookie 换新的 AT)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 2. Create Checkout │ (拿 AT 创建 checkout session)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 3. Stripe Init │ (初始化支付页面状态)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 4. Update OAI Taxes │ (通知 OpenAI 更新税务)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 5. Stripe Tax Region │ (更新 Stripe 税务区域)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 6. Stripe Customer Data │ (更新客户信息)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 7. OAI Checkout Snapshot │ (保存 checkout 快照)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 8. Pre-Confirm │ (部分支付方式需要)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 9. Create Payment Method │ (创建 PM，类型=ideal/upi/pix...)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 10. Confirm │ (确认支付，触发重定向)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 11. Approve │ (如果需要额外批准)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 12. Extract Redirect URL │ (从 confirm 响应中提取跳转链接)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每一步都有自己的参数格式和必要的状态管理。Stripe 的 Checkout Session 是有状态的——它跟踪你的 &lt;code&gt;eid&lt;/code&gt;（element ID）、&lt;code&gt;mrid&lt;/code&gt;（merchant reference ID）、&lt;code&gt;expected_amount&lt;/code&gt; 等等。如果你跳过了某一步或者参数不对，后续步骤就会报错。&lt;/p&gt;
&lt;h3 id="step-4提取支付链接"&gt;Step 4：提取支付链接
&lt;/h3&gt;&lt;p&gt;第 10 步 &lt;code&gt;Confirm&lt;/code&gt; 之后，如果支付方式是重定向类型（iDEAL、UPI、PIX 等都是），Stripe 会在响应中返回一个 &lt;code&gt;redirect_url&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;requires_action&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;next_action&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;redirect_to_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;redirect_to_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://hooks.stripe.com/redirect/authenticate/src_xxx?client_secret=...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个 URL 就是最终的支付链接。用户在浏览器中打开它，会被重定向到对应的支付方式页面（iDEAL 的银行选择页、UPI 的付款确认页、PIX 的二维码页面等）。完成支付后，Stripe webhook 通知 OpenAI，OpenAI 确认订阅生效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;整个流程，金额由 Stripe 的价格表决定，提链工具不篡改任何金额字段。&lt;/strong&gt; 用户付的就是对应国家/地区的标准月费。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三stripe-checkout-session-的内部结构"&gt;三、Stripe Checkout Session 的内部结构
&lt;/h2&gt;&lt;p&gt;拆开看，Stripe Checkout Session 里藏了不少有趣的东西。&lt;/p&gt;
&lt;p&gt;第 3 步 &lt;code&gt;Stripe Init&lt;/code&gt; 调用的是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/payment_pages/{oaics_xxx}/init
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;响应中最关键的几个字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;payment_method_types&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;card&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ideal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;line_items&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ChatGPT Plus subscription&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eur&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;shipping_address_collection&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;payment_method_configuration&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;merchant_reference_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mri_xxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;customer_session_client_secret&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cuss_xxx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;session_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;oaics_xxx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;payment_method_types&lt;/code&gt; 是关键——它决定了这个 Checkout Session 支持哪些支付方式。同一个接口，传不同的 &lt;code&gt;country&lt;/code&gt; / &lt;code&gt;currency&lt;/code&gt;，返回的 &lt;code&gt;payment_method_types&lt;/code&gt; 就不同。&lt;/p&gt;
&lt;p&gt;这也解释了为什么 OpenAI 前端只显示信用卡——它在创建 Checkout Session 时没有传目标国家的 &lt;code&gt;billing_details&lt;/code&gt;，或者传的是用户账号的注册国家（通常是 US），所以 Stripe 只返回 &lt;code&gt;[&amp;quot;card&amp;quot;]&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四八种支付方式的技术对比"&gt;四、八种支付方式的技术对比
&lt;/h2&gt;&lt;p&gt;每种支付方式在 Stripe 层面的行为略有不同：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;支付方式&lt;/th&gt;
 &lt;th&gt;PM Type&lt;/th&gt;
 &lt;th&gt;国家&lt;/th&gt;
 &lt;th&gt;货币&lt;/th&gt;
 &lt;th&gt;需要 pre_confirm&lt;/th&gt;
 &lt;th&gt;重定向类型&lt;/th&gt;
 &lt;th&gt;特殊处理&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;iDEAL&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ideal&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;NL&lt;/td&gt;
 &lt;td&gt;EUR&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;银行选择页&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UPI&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;upi&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;IN&lt;/td&gt;
 &lt;td&gt;INR&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;VPA 输入页&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;PIX&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pix&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;BR&lt;/td&gt;
 &lt;td&gt;BRL&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;二维码页&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;TWINT&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;twint&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CH&lt;/td&gt;
 &lt;td&gt;CHF&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;App 跳转&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Kakao Pay&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;kakao_pay&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;KR&lt;/td&gt;
 &lt;td&gt;KRW&lt;/td&gt;
 &lt;td&gt;✓&lt;/td&gt;
 &lt;td&gt;Kakao 确认页&lt;/td&gt;
 &lt;td&gt;需要 pre_confirm 调用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;BLIK&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;blik&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PL&lt;/td&gt;
 &lt;td&gt;PLN&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;6位码输入&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;MoMo&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;momo&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;VN&lt;/td&gt;
 &lt;td&gt;VND&lt;/td&gt;
 &lt;td&gt;✓&lt;/td&gt;
 &lt;td&gt;MoMo App&lt;/td&gt;
 &lt;td&gt;需要 pre_confirm 调用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GCash&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;gcash&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PH&lt;/td&gt;
 &lt;td&gt;PHP&lt;/td&gt;
 &lt;td&gt;✗&lt;/td&gt;
 &lt;td&gt;GCash 确认页&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;大多数支付方式流程一致：创建 PM → Confirm → 提取 redirect URL。但 Kakao Pay 和 MoMo 需要额外的 &lt;code&gt;pre_confirm&lt;/code&gt; 调用——如果跳过这一步，Confirm 会返回 &lt;code&gt;incomplete&lt;/code&gt; 状态，没有 redirect URL。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pre_confirm&lt;/code&gt; 的请求格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;POST https://api.stripe.com/v1/payment_pages/{oaics_xxx}/pre_confirm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Content-Type: application/x-www-form-urlencoded
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;expected_payment_method_type=kakao_pay
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看起来简单，但如果你不知道有这一步，Kakao Pay 的提链就会卡在最后一步——所有参数都对了，就是拿不到链接。这类细节只有通过 HAR 抓包 Stripe 的完整结账流程才能发现。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五从-0-php-到提链漏洞与工具的边界"&gt;五、从 0 PHP 到提链——漏洞与工具的边界
&lt;/h2&gt;&lt;p&gt;上一篇文章分析了 &lt;a class="link" href="https://blog.7qiang.com/posts/chatgpt-plus-0php-cross-region-pricing-exploit-2026/" target="_blank" rel="noopener"
 &gt;0 PHP 攻击&lt;/a&gt;，里面提到第三方工具在创建 Checkout Session 时可能注入了零元参数（如 &lt;code&gt;promo_campaign&lt;/code&gt;）。那么问题来了：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;提链工具和那个&amp;quot;CDK 提炼&amp;quot;工具是一回事吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不是。区别在于：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;0 PHP “提炼&amp;quot;工具&lt;/th&gt;
 &lt;th&gt;正常提链工具&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;目的&lt;/td&gt;
 &lt;td&gt;白嫖（amount = 0）&lt;/td&gt;
 &lt;td&gt;正常付款&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;是否注入优惠码&lt;/td&gt;
 &lt;td&gt;是（&lt;code&gt;promo_campaign&lt;/code&gt;、&lt;code&gt;discount&lt;/code&gt; 等）&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;金额来源&lt;/td&gt;
 &lt;td&gt;工具操纵&lt;/td&gt;
 &lt;td&gt;Stripe 价格表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;合法性&lt;/td&gt;
 &lt;td&gt;灰色/违法&lt;/td&gt;
 &lt;td&gt;正常商业行为&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;正常的提链工具&lt;strong&gt;不注入任何优惠参数&lt;/strong&gt;。它只是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用你的 AT 创建一个以目标国家/货币计价的 Checkout Session&lt;/li&gt;
&lt;li&gt;走完 Stripe 的协议流程&lt;/li&gt;
&lt;li&gt;把 redirect URL 返回给你&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你付的是 Stripe 价格表上对应区域的标准价格——荷兰 €20/月，印度 ₹1,950/月，巴西 R$99.90/月。没有优惠码，没有金额篡改。&lt;/p&gt;
&lt;p&gt;正常的提链工具的设计原则应该是：&lt;strong&gt;不注入 &lt;code&gt;promo_campaign&lt;/code&gt;，不传 &lt;code&gt;discount&lt;/code&gt;，不覆盖 &lt;code&gt;amount&lt;/code&gt;。&lt;/strong&gt; 工具只做一件事——把 Stripe 的本地支付能力释放出来，让没有信用卡的用户也能正常订阅。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六协议细节那些让你卡住的坑"&gt;六、协议细节——那些让你卡住的坑
&lt;/h2&gt;&lt;p&gt;如果你自己尝试过写提链脚本，你一定踩过这些坑。&lt;/p&gt;
&lt;h3 id="坑-1ip-一致性"&gt;坑 1：IP 一致性
&lt;/h3&gt;&lt;p&gt;Stripe Checkout Session 在创建和确认时需要使用同一个 IP。如果你用代理 A 创建了 Checkout Session，又用代理 B 去 Confirm——Stripe 会返回 &lt;code&gt;invalid_request_error&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这不是 Stripe 的 bug，是安全机制。Stripe 检测到 session 的创建 IP 和确认 IP 不一致，会认为可能是中间人攻击。&lt;/p&gt;
&lt;p&gt;解决方案：&lt;strong&gt;整个 12 步流程使用同一个 HTTP client（或 cookie jar），确保所有请求走同一个出口 IP。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="坑-2expected_amount"&gt;坑 2：&lt;code&gt;expected_amount&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;Stripe 的 Confirm 请求需要传 &lt;code&gt;expected_amount&lt;/code&gt; 参数，值必须和 Checkout Session 的金额一致。这个值从哪来？&lt;/p&gt;
&lt;p&gt;最准确的来源是第 4 步 &lt;code&gt;Update Taxes&lt;/code&gt; 的响应。这一步把账单地址传给 OpenAI，OpenAI 计算含税金额后写入 Checkout Session，然后返回一个 snapshot，里面有 &lt;code&gt;amount_total&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;snapshot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;amount_total&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eur&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你用 Init 步骤的金额去 Confirm，可能会因为税后金额不一致而失败。&lt;/p&gt;
&lt;h3 id="坑-3stripe-session-state"&gt;坑 3：Stripe Session State
&lt;/h3&gt;&lt;p&gt;Stripe 的 Checkout Session 维护了一个内部状态。每次 API 调用后，响应里都会更新 &lt;code&gt;eid&lt;/code&gt;、&lt;code&gt;mrid&lt;/code&gt; 等字段。下一次调用必须带上最新的状态值。&lt;/p&gt;
&lt;p&gt;这意味着你不能简单地并行调用 12 步——必须严格按顺序执行，每一步用上一步返回的最新状态。&lt;/p&gt;
&lt;h3 id="坑-4accept-language-和-guid"&gt;坑 4：&lt;code&gt;Accept-Language&lt;/code&gt; 和 &lt;code&gt;guid&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;这两个是容易忽略的细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stripe API 会根据 &lt;code&gt;Accept-Language&lt;/code&gt; 请求头返回不同的 &lt;code&gt;locale&lt;/code&gt; 配置。如果你不传，默认是 &lt;code&gt;en-US&lt;/code&gt;，但某些支付方式在特定 locale 下行为不同。&lt;/li&gt;
&lt;li&gt;Stripe 的某些内部 API 需要一个 &lt;code&gt;guid&lt;/code&gt; 参数，格式是 &lt;code&gt;xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx&lt;/code&gt;（UUID v4）。不是随便写的——格式不对会被拒绝。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="坑-5超时"&gt;坑 5：超时
&lt;/h3&gt;&lt;p&gt;整个流程从创建 Checkout Session 到拿到 redirect URL，通常需要 10~30 秒。某些支付方式（如 Kakao Pay）可能需要更长时间，因为 Stripe 需要和第三方支付系统交互。&lt;/p&gt;
&lt;p&gt;如果 Confirm 之后没有立刻返回 redirect URL，需要轮询 Init 接口。URL 可能在 Confirm 后几秒到几十秒内才出现。我们的工具最多等 90 秒——超过这个时间通常意味着哪里出了问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七开源提链脚本"&gt;七、开源提链脚本
&lt;/h2&gt;&lt;p&gt;说了这么多原理，给一些现成的实现参考。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;⚠️ 时效性声明&lt;/strong&gt;：以下脚本收集于 2026 年 7 月。OpenAI/Stripe 的 API 接口、Stripe runtime 版本、风控策略随时可能变更，脚本&lt;strong&gt;可能已不可用&lt;/strong&gt;。仅供学习协议流程和理解技术原理，不保证当前可运行。使用前请自行验证。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="多支付方式提链套件"&gt;多支付方式提链套件
&lt;/h3&gt;&lt;p&gt;来源：社区开源的 &lt;code&gt;ideal-link-extractor&lt;/code&gt;，MIT License。&lt;/p&gt;
&lt;p&gt;包含 6 种支付方式的独立提取脚本：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;脚本&lt;/th&gt;
 &lt;th&gt;支付方式&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ideal_qr_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;iDEAL（荷兰）&lt;/td&gt;
 &lt;td&gt;核心脚本（3263 行），其他脚本的参考实现&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;upi/upi_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;UPI（印度）&lt;/td&gt;
 &lt;td&gt;含多代理轮转、并行模式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;pix/pix_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PIX（巴西）&lt;/td&gt;
 &lt;td&gt;二维码提取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;twint/twint_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;TWINT（瑞士）&lt;/td&gt;
 &lt;td&gt;App 跳转链接&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;kakao/kakao_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Kakao Pay（韩国）&lt;/td&gt;
 &lt;td&gt;含 pre_confirm 处理&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;blik/blik_qr_extract.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;BLIK（波兰）&lt;/td&gt;
 &lt;td&gt;6 位码输入链接&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;detect_payment_methods.py&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;通用&lt;/td&gt;
 &lt;td&gt;按国家检测可用的 Stripe 支付方式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;依赖：&lt;code&gt;requests&lt;/code&gt;、&lt;code&gt;curl_cffi&lt;/code&gt;、&lt;code&gt;qrcode[pil]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;基本用法（以 UPI 为例）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install requests curl_cffi
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;UPI_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;eyJhbGciOi...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;UPI_PROXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;socks5://user:pass@host:port&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# 自备代理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python upi_extract.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个脚本通过环境变量配置代理（&lt;code&gt;XXX_PROXY&lt;/code&gt;）和 Token（&lt;code&gt;XXX_TOKEN&lt;/code&gt; 或 &lt;code&gt;token.txt&lt;/code&gt; 文件）。代理需自备——脚本不内置任何代理。&lt;/p&gt;
&lt;h3 id="momo-提取脚本越南"&gt;MoMo 提取脚本（越南）
&lt;/h3&gt;&lt;p&gt;独立维护的 MoMo/Kakao 脚本集，包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kakao_extract.py&lt;/code&gt;——共享的会话管理和 Stripe 协议辅助函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;momo_channel_probe.py&lt;/code&gt;——只读模式探测 MoMo 通道可用性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;momo_probe.py&lt;/code&gt;——默认只读，设置 &lt;code&gt;MOMO_EXTRACT_REDIRECT=1&lt;/code&gt; 才尝试提取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;依赖额外的 Playwright（需要 Chromium）。&lt;/p&gt;
&lt;h3 id="脚本的核心设计"&gt;脚本的核心设计
&lt;/h3&gt;&lt;p&gt;这些脚本的技术亮点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;代理状态持久化&lt;/strong&gt;——&lt;code&gt;proxy_state.json&lt;/code&gt; 记录每个代理的健康状态、成功/失败计数、冷却时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志脱敏&lt;/strong&gt;——自动将代理地址、Token 等敏感信息替换为安全标签&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多 Worker 并行&lt;/strong&gt;——支持多线程并发提取，自动分配代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stripe 协议完整实现&lt;/strong&gt;——Session state 管理、&lt;code&gt;eid&lt;/code&gt;/&lt;code&gt;mrid&lt;/code&gt; 追踪、tax region 更新，完整复刻浏览器行为&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：部分脚本包含 &lt;code&gt;promo_campaign&lt;/code&gt; 注入逻辑和 &lt;code&gt;REQUIRE_ZERO&lt;/code&gt; 选项（用于上一篇文章分析的 0 PHP 攻击路径）。这些属于漏洞利用代码，&lt;strong&gt;不建议使用&lt;/strong&gt;——OpenAI 大概率已做修复，强行使用可能导致账号风控。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="八为什么-openai-不直接提供这些支付方式"&gt;八、为什么 OpenAI 不直接提供这些支付方式？
&lt;/h2&gt;&lt;p&gt;好问题。Stripe 支持它们，OpenAI 用的是 Stripe，为什么不在结账页面上显示？&lt;/p&gt;
&lt;p&gt;几个可能的原因：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;合规成本&lt;/strong&gt;：每个国家的本地支付方式有不同的合规要求（反洗钱、实名验证等）。支持 iDEAL 意味着要满足荷兰的金融监管要求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;退款风险&lt;/strong&gt;：某些本地支付方式的退款/dispute 流程和信用卡不同。PIX 的退款机制、UPI 的 chargeback 流程，都需要额外的运营投入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;税务复杂度&lt;/strong&gt;：不同国家的增值税率不同，账单格式要求不同。OpenAI 需要为每个国家维护正确的税务处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优先级&lt;/strong&gt;：信用卡覆盖了 OpenAI 的核心市场（北美、欧洲）。本地支付方式对应的市场（东南亚、拉美、南亚）目前可能不是优先级。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但 Stripe 的能力已经在那里了。&lt;code&gt;payment_method_types&lt;/code&gt; 里已经包含了这些方式。OpenAI 只需要在前端把选项打开。在此之前——提链工具就是桥梁。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="九和-0-php-漏洞的关系一张图说清"&gt;九、和 0 PHP 漏洞的关系——一张图说清
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 正常提链工具 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ country=NL, currency=EUR │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ NO promo_campaign │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → amount = €20 (Stripe 价格表) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → redirect URL → iDEAL 付款 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────┬───────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 同一个 API │ 同一个 API
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────▼───────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ OpenAI /payments/checkout API │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ + Stripe Checkout Session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────┬───────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────▼───────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 0 PHP 攻击工具 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ country=PH, currency=PHP │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ + promo_campaign injection │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ + cross-region confusion │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → amount = ₱0 (被操纵) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → PH BIN 卡完成支付 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同一个 API，两种用法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提链&lt;/strong&gt;：合法利用 Stripe 的本地支付能力，正常价格&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0 PHP&lt;/strong&gt;：利用跨区信号碎片化 + 参数注入，把价格打到零&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;提链不是漏洞利用。它只是 Stripe 本来就有的能力，被 OpenAI 前端隐藏了而已。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="十写在最后"&gt;十、写在最后
&lt;/h2&gt;&lt;p&gt;提链的本质是一个简单的事实：&lt;strong&gt;Stripe 是一个全球支付平台，它天然支持几十种本地支付方式。OpenAI 的 UI 做了限制，但 API 没有。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从技术角度看，12 步协议流程的每一步都有其必要性——IP 一致性、状态管理、税务更新、pre_confirm。跳过任何一步都会导致最终拿不到 redirect URL。这也是为什么&amp;quot;提链&amp;quot;不是简单地抓个包就能搞定的——你需要理解 Stripe 的完整 Checkout 流程。&lt;/p&gt;
&lt;p&gt;从商业角度看，提链让全球用户有了一种不依赖信用卡的方式来使用 ChatGPT。在信用卡渗透率不到 10% 的印度，UPI 是 8 亿人的默认支付方式。提链本身不是什么灰色操作——它只是把 Stripe 的能力释放给了真正需要的人。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;最后的最后&lt;/strong&gt;：本文提到的所有脚本和协议细节都有时效性。OpenAI 和 Stripe 的接口在持续变化——Stripe runtime version 会更新，API 字段会调整，风控规则会收紧。今天能跑的脚本，明天可能就 403 了。理解原理比收藏脚本更重要。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="附录直卡绑定另一条路"&gt;附录：直卡绑定——另一条路
&lt;/h2&gt;&lt;p&gt;除了提链，还有一种完全不同的思路：&lt;strong&gt;直接给 ChatGPT 账号绑一张卡，然后正常走 checkout。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就是&amp;quot;直卡焚决&amp;quot;方法的核心。它不绕过前端、不走第三方支付——它解决的是&amp;quot;没有美区信用卡&amp;quot;这个前置问题。&lt;/p&gt;
&lt;h3 id="原理"&gt;原理
&lt;/h3&gt;&lt;p&gt;OpenAI 的 &lt;code&gt;/backend-api/payments/payment_method&lt;/code&gt; 接口支持创建 Stripe &lt;code&gt;SetupIntent&lt;/code&gt;——这是 Stripe 的&amp;quot;先绑卡不扣款&amp;quot;机制。绑上之后，下次走 checkout 时就有卡可用了。&lt;/p&gt;
&lt;p&gt;配套的控制台脚本（在 chatgpt.com 的 Console 里运行）做了这几件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;自动发现 Stripe 公钥&lt;/strong&gt;——OpenAI 有两个 Stripe 商户分片（&lt;code&gt;KslHRdbaPg&lt;/code&gt; 和 &lt;code&gt;C6h1nxGoI3&lt;/code&gt;），脚本通过 &lt;code&gt;retrieveSetupIntent&lt;/code&gt; 自动匹配当前账号属于哪个分片&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建 SetupIntent&lt;/strong&gt;——调用 OpenAI 的 &lt;code&gt;payment_method&lt;/code&gt; API，拿到 &lt;code&gt;client_secret&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渲染 Stripe Card Element&lt;/strong&gt;——在页面上弹出一个模态框，内嵌 Stripe 的标准卡输入组件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确认绑定&lt;/strong&gt;——&lt;code&gt;stripe.confirmCardSetup&lt;/code&gt; + &lt;code&gt;set_as_default_payment_method: true&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 关键调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confirmCardSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;payment_method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cardElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;billing_details&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;allow_redisplay&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;always&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;set_as_default_payment_method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;绑卡成功后，脚本还会调用 &lt;code&gt;/backend-api/payments/payment_methods&lt;/code&gt; 拉取当前账号的所有支付方式列表，用 &lt;code&gt;console.table&lt;/code&gt; 打印出来。你可以看到新绑的卡已经成为默认支付方式。&lt;/p&gt;
&lt;h3 id="和提链的关系"&gt;和提链的关系
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;直卡绑定&lt;/strong&gt;：解决&amp;quot;没有卡&amp;quot;的问题。需要有一张能过 Stripe AVS/3DS 验证的实体或虚拟卡。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提链&lt;/strong&gt;：解决&amp;quot;不想/不能用信用卡&amp;quot;的问题。走本地支付方式，完全不涉及信用卡。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两种方法互补——有卡的用直卡，没卡的用提链。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="相关阅读"&gt;相关阅读
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/chatgpt-plus-0php-cross-region-pricing-exploit-2026/" target="_blank" rel="noopener"
 &gt;0 PHP 白嫖 ChatGPT Plus — 跨区定价混淆攻击的完整技术拆解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-google-play-subscription-transfer/" target="_blank" rel="noopener"
 &gt;ChatGPT Plus Google Play 订阅转移漏洞分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;RevenueCat 凭证转移漏洞——匿名购买 + restore 归属偷渡&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/google-play-ccmax-proration-vulnerability-2026/" target="_blank" rel="noopener"
 &gt;Google Play CC Max 比例分配漏洞&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>0 PHP 白嫖 ChatGPT Plus — 跨区定价混淆攻击的完整技术拆解</title><link>https://blog.7qiang.com/posts/chatgpt-plus-0php-cross-region-pricing-exploit-2026/</link><pubDate>Tue, 28 Jul 2026 18:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/chatgpt-plus-0php-cross-region-pricing-exploit-2026/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post 0 PHP 白嫖 ChatGPT Plus — 跨区定价混淆攻击的完整技术拆解" /&gt;&lt;section class="xiaoyao-contact-card" aria-label="联系逍遥"&gt;
 &lt;img class="xiaoyao-contact-card__qr" src="https://blog.7qiang.com/contact-qr.png" width="690" height="690" loading="lazy" decoding="async" alt="逍遥微信二维码"&gt;
 &lt;div class="xiaoyao-contact-card__content"&gt;
 &lt;h3 class="xiaoyao-contact-card__title"&gt;联系逍遥&lt;/h3&gt;
 &lt;p class="xiaoyao-contact-card__description"&gt;扫码添加微信，或点击下方按钮复制联系方式。&lt;/p&gt;
 &lt;div class="xiaoyao-contact-buttons" data-contact-buttons&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--wechat" type="button" data-copy-contact="plus6566" data-copy-label="微信号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;微信&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;plus6566&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--qq" type="button" data-copy-contact="826215906" data-copy-label="QQ 号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;QQ&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;826215906&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;span class="xiaoyao-contact-feedback" role="status" aria-live="polite"&gt;&lt;/span&gt;
&lt;/div&gt;

 &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;进微信群请联系博主，各位觉得文章对你有帮助的话可否打赏一些呀~&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;⚠️ 免责声明&lt;/strong&gt;：本文仅供安全研究与技术讨论。文中不提供可直接复用的攻击工具或完整利用脚本。利用类似手段对正式服务进行未授权操作属违法行为，后果自负。本文目的是帮助支付系统开发者理解跨区定价攻击面并加固防御。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;这两天群里炸了。&lt;/p&gt;
&lt;p&gt;有人甩出一张截图：Stripe 结账页面，产品写着 “ChatGPT Plus”，金额一栏赫然显示 &lt;strong&gt;₱0.00 PHP&lt;/strong&gt;。菲律宾比索，零元，提交即开通。&lt;/p&gt;
&lt;p&gt;评论区画风可想而知——“假的吧&amp;quot;“PS 的吧&amp;quot;“你怎么不说 Plus 倒找你钱”。&lt;/p&gt;
&lt;p&gt;然后陆陆续续有人贴出了完整流程，甚至还配了视频录屏。操作步骤不复杂，总共四步，不需要 Root，不需要 Frida，不需要改一行代码。唯一的技术含量在于——&lt;strong&gt;你得知道用什么顺序把哪些区域串起来。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就有意思了。之前我们拆过 &lt;a class="link" href="https://blog.7qiang.com/posts/google-play-ccmax-proration-vulnerability-2026/" target="_blank" rel="noopener"
 &gt;prorationMode hook&lt;/a&gt;（改一个 &lt;code&gt;putInt&lt;/code&gt; 白嫖 Claude Max）、拆过 &lt;a class="link" href="https://blog.7qiang.com/posts/claude-cassia-mock-payment-bypass-analysis/" target="_blank" rel="noopener"
 &gt;焚决脚本&lt;/a&gt;（劫持 &lt;code&gt;checkout_capabilities&lt;/code&gt; 走 SEPA 假账号）、拆过 &lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;RevenueCat 凭证转移&lt;/a&gt;（匿名购买 + restore 归属偷渡）。那些多少都是&amp;quot;改代码&amp;quot;的路子——Hook 内存、注入响应、篡改参数。&lt;/p&gt;
&lt;p&gt;但这次不一样。这次&lt;strong&gt;什么都没改&lt;/strong&gt;。没有脚本，没有 Hook，没有中间人。攻击者只是以一种特定的顺序访问了几个网页，然后 Stripe 自己就吐出了 0 元账单。&lt;/p&gt;
&lt;p&gt;今天把它完整拆开。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一攻击全景四步从-jp-到-ph从-20-到-0"&gt;一、攻击全景：四步，从 JP 到 PH，从 $20 到 ₱0
&lt;/h2&gt;&lt;p&gt;先把流传的步骤还原一下：&lt;/p&gt;
&lt;h3 id="step-1日本节点注册-openai-账号"&gt;Step 1：日本节点注册 OpenAI 账号
&lt;/h3&gt;&lt;p&gt;挂 JP 代理，开一个干净的浏览器 Profile（指纹浏览器或者 Chrome 新 Profile），去 OpenAI 官网正常注册，邮箱验证，登录确认。&lt;/p&gt;
&lt;p&gt;此时你的账号状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;account.locale = &amp;#34;ja-JP&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;account.billing_country = &amp;#34;JP&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;account.currency = &amp;#34;JPY&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OpenAI 在注册时根据你的 IP 地理位置初始化账号的计费区域。&lt;strong&gt;这一步的目的不是&amp;quot;要日本&amp;quot;本身，而是要一个非美区的初始定价锚点。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="step-2切美国节点提取-access-token"&gt;Step 2：切美国节点，提取 Access Token
&lt;/h3&gt;&lt;p&gt;保持同一个浏览器 Profile，VPN 切到 US 节点，重新登录刚才注册的账号。然后新标签页打开：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://chatgpt.com/api/auth/session
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;浏览器返回一个 JSON，里面有 &lt;code&gt;accessToken&lt;/code&gt; 字段——一个标准 JWT。复制保存。&lt;/p&gt;
&lt;p&gt;此时你的 session 状态出现了第一层矛盾：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;account.billing_country = &amp;#34;JP&amp;#34; ← 注册时写入，持久化在 OpenAI 数据库
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;session.ip_country = &amp;#34;US&amp;#34; ← 当前 IP 推断，存在 session/edge 层
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-3第三方工具生成-checkout-链接"&gt;Step 3：第三方工具生成 Checkout 链接
&lt;/h3&gt;&lt;p&gt;打开某个第三方&amp;quot;CDK 提炼&amp;quot;工具站点（这类工具本质上就是一个 AT → Stripe Checkout Session 的代理），把 Access Token 粘进去，点生成。&lt;/p&gt;
&lt;p&gt;工具返回一个链接，格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://chatgpt.com/checkout/openai_llc/oaics_xxxxxxxxxxxxxxxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;oaics_&lt;/code&gt; 是 OpenAI 的 Stripe Checkout Session ID 前缀。这个 session 是 OpenAI 后端基于你的 AT 创建的，包含了产品、价格、货币等信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键问题来了：这个 Checkout Session 的 currency 和 amount 是怎么决定的？&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="step-4打开链接惊喜时刻"&gt;Step 4：打开链接，惊喜时刻
&lt;/h3&gt;&lt;p&gt;在美国节点下打开这个 oaics 链接。Stripe 结账页面加载出来，你看到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ChatGPT Plus
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;₱0.00 PHP / month
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;菲律宾比索。零元。&lt;/p&gt;
&lt;p&gt;填入指定 BIN 的卡片信息（523686 或 4513），美国账单地址，提交。&lt;/p&gt;
&lt;p&gt;Stripe 收了一笔 0 元交易，OpenAI 后端确认 checkout session 成功，权益生效。回到 ChatGPT 首页，左上角已经是 Plus 了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二为什么是-0-php三种假说"&gt;二、为什么是 0 PHP？——三种假说
&lt;/h2&gt;&lt;p&gt;先澄清一个重要事实：&lt;strong&gt;OpenAI 在菲律宾是有明确定价的&lt;/strong&gt;，ChatGPT Plus 的 PH 区定价大约是 ₱990 PHP/月。所以这不是简单的&amp;quot;价格表空洞导致 fallback 到 0”——如果定价系统正常查 PH 价格表，应该返回 ₱990，不是 ₱0。&lt;/p&gt;
&lt;p&gt;那 0 是怎么来的？没有对 Checkout Session 创建过程的完整抓包，我们只能做推断。以下三种假说按可能性排序。&lt;/p&gt;
&lt;h3 id="假说一第三方工具在创建-checkout-session-时注入了零元参数最可能"&gt;假说一：第三方工具在创建 Checkout Session 时注入了零元参数（最可能）
&lt;/h3&gt;&lt;p&gt;OpenAI 的 &lt;code&gt;/backend-api/payments/checkout&lt;/code&gt; 接口接受多个参数来创建 Stripe Checkout Session。如果这个接口接受客户端传入的 &lt;code&gt;discount&lt;/code&gt;、&lt;code&gt;coupon&lt;/code&gt;、&lt;code&gt;promotion_code&lt;/code&gt; 或类似参数，且&lt;strong&gt;后端没做资格校验&lt;/strong&gt;——工具直接传了一个 100% 折扣的 coupon code 或者 &lt;code&gt;amount_override: 0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这和之前 &lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;RevenueCat 文章&lt;/a&gt;里分析过的 &lt;code&gt;eligible_promo_campaigns&lt;/code&gt; 注入如出一辙：客户端声称&amp;quot;我有优惠资格”，后端不校验就信了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 工具的真实请求可能长这样
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;plus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;promotion_code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;某个内部免费试用码&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 或者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;billing_country&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PH&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 或者更直接的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;price_override&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;JP 注册 + US 登录制造的区域歧义，可能不是直接触发 0 元的原因，而是&lt;strong&gt;绕过风控检查的前置条件&lt;/strong&gt;——当账号区域和 IP 区域不一致时，后端对 checkout 参数的校验逻辑可能走入了一个宽松的分支。&lt;/p&gt;
&lt;h3 id="假说二跨区信号冲突导致定价路由进入异常分支"&gt;假说二：跨区信号冲突导致定价路由进入异常分支
&lt;/h3&gt;&lt;p&gt;当 OpenAI 创建 Stripe Checkout Session 时，面前有至少四个区域信号：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;信号来源&lt;/th&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;决定时机&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;账号注册地&lt;/td&gt;
 &lt;td&gt;JP&lt;/td&gt;
 &lt;td&gt;注册时固化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;当前 session IP&lt;/td&gt;
 &lt;td&gt;US&lt;/td&gt;
 &lt;td&gt;每次请求实时推断&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stripe 卡 BIN 发行国&lt;/td&gt;
 &lt;td&gt;PH&lt;/td&gt;
 &lt;td&gt;填卡时由 Stripe 推断&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;浏览器 Accept-Language&lt;/td&gt;
 &lt;td&gt;取决于浏览器设置&lt;/td&gt;
 &lt;td&gt;每次请求携带&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;正常场景下这四个信号一致——美国人在美国用美国卡买东西，直接查 US 价格表。&lt;/p&gt;
&lt;p&gt;但当 JP ≠ US ≠ PH 三个信号同时存在时，定价系统需要做一个选择。如果选择逻辑是 &lt;code&gt;if (account.country != ip.country) { use card.country }&lt;/code&gt; 这种优先级策略，而 PH 价格表虽然存在但在某个&lt;strong&gt;子路径&lt;/strong&gt;（比如&amp;quot;非本地注册用户+跨区IP&amp;quot;的特殊定价分支）中没有配置——就可能在这个特殊分支里 fallback 到 0。&lt;/p&gt;
&lt;p&gt;换句话说：&lt;strong&gt;PH 的主价格表有值（₱990），但某个异常处理路径的价格映射没覆盖到 PH&lt;/strong&gt;，攻击者通过区域信号碎片化精确命中了这条路径。&lt;/p&gt;
&lt;h3 id="假说三stripe-checkout-session-的-line_items-被工具篡改"&gt;假说三：Stripe Checkout Session 的 line_items 被工具篡改
&lt;/h3&gt;&lt;p&gt;Stripe &lt;code&gt;checkout.sessions.create&lt;/code&gt; 的 &lt;code&gt;line_items&lt;/code&gt; 参数包含 &lt;code&gt;price&lt;/code&gt; 或 &lt;code&gt;price_data&lt;/code&gt;。如果 OpenAI 的接口允许客户端指定 &lt;code&gt;price_data.unit_amount&lt;/code&gt;（哪怕是间接的），工具就能在创建 session 时直接把金额写成 0。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;line_items: [{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; price_data: {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; currency: &amp;#34;php&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; unit_amount: 0, // 直接指定 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; product: &amp;#34;prod_xxx&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; recurring: { interval: &amp;#34;month&amp;#34; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; quantity: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种情况下 PH BIN 的作用不是&amp;quot;触发 PH 价格表&amp;quot;，而是&lt;strong&gt;让 currency 字段说得通&lt;/strong&gt;——如果你传 &lt;code&gt;currency: &amp;quot;php&amp;quot;&lt;/code&gt; 但卡是 US 卡，Stripe 可能会有额外的 currency mismatch 警告。PH 卡 + PHP 货币是自洽的。&lt;/p&gt;
&lt;h3 id="为什么是-ph-bin"&gt;为什么是 PH BIN？
&lt;/h3&gt;&lt;p&gt;无论哪种假说，流传的两个 BIN 都有其作用：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;BIN&lt;/th&gt;
 &lt;th&gt;网络&lt;/th&gt;
 &lt;th&gt;发行国&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;523686&lt;/td&gt;
 &lt;td&gt;Mastercard&lt;/td&gt;
 &lt;td&gt;菲律宾&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4513xx&lt;/td&gt;
 &lt;td&gt;Visa&lt;/td&gt;
 &lt;td&gt;取决于具体发行行&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;523686 开头的卡填入 Stripe 表单时，Stripe 内部标记 &lt;code&gt;payment_method.card.country = &amp;quot;PH&amp;quot;&lt;/code&gt;。这个信号在整个支付流中传播。PH BIN 的作用至少有两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;让 PHP 货币的 checkout session 能正常完成&lt;/strong&gt;——卡的发行国和结账货币匹配&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可能绕过 OpenAI 的 card-country vs account-country 风控规则&lt;/strong&gt;——PH 卡付 PHP 金额在 Stripe 层面是&amp;quot;正常交易&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="三jp-注册的作用制造区域身份分裂"&gt;三、JP 注册的作用——制造&amp;quot;区域身份分裂&amp;quot;
&lt;/h2&gt;&lt;p&gt;你可能会问：为什么不直接在美国注册、美国提 Token、用 PH 卡付？&lt;/p&gt;
&lt;p&gt;答案是：&lt;strong&gt;直接美区注册的账号，定价系统的行为是确定性的——走 US 价格表，$20 USD，没有歧义可利用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;JP 注册的作用是制造一个&lt;strong&gt;区域身份不确定&lt;/strong&gt;的账号。当账号的 billing_country 是 JP，session IP 是 US，这两个信号已经矛盾了。定价系统在处理这种矛盾时，可能会：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;走入一个&lt;strong&gt;异常处理分支&lt;/strong&gt;，该分支的参数校验比正常路径更宽松&lt;/li&gt;
&lt;li&gt;允许第三方工具注入的额外参数（如 currency、discount）覆盖默认行为&lt;/li&gt;
&lt;li&gt;使用一个与主价格表不同的&lt;strong&gt;备用定价逻辑&lt;/strong&gt;，而这个逻辑有漏洞&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用状态机的视角看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 注册时: JP │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ locale=ja-JP │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────┬───────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌──────▼───────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 登录时: US │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ip_country=US│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ≠ locale │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────┬───────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌──────▼───────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 创建 Checkout │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ JP ≠ US → 歧义 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → 进入异常分支 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → 参数校验宽松 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────┬───────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌──────▼───────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 工具注入参数 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ + Card BIN: PH │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → amount = 0 PHP │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └──────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;三个不同的区域信号（JP / US / PH）制造了歧义，歧义打开了异常路径，异常路径上的校验缺失被利用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是一个经典的安全反模式：当多个权威源对同一个问题给出不同答案时，系统在歧义中放松了校验——不是直接返回 0，而是&lt;strong&gt;给了攻击者操纵结果的空间&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四第三方提炼工具在干什么"&gt;四、第三方&amp;quot;提炼工具&amp;quot;在干什么？
&lt;/h2&gt;&lt;p&gt;流程里的那个第三方网站（&lt;code&gt;sms.linlinflow.ccwu.cc&lt;/code&gt;），名字叫&amp;quot;CDK 提炼&amp;quot;，听着玄乎，其实它干的事非常直白：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;接收你的 Access Token&lt;/li&gt;
&lt;li&gt;用这个 AT 调用 OpenAI 后端 API，创建一个 Stripe Checkout Session&lt;/li&gt;
&lt;li&gt;把 Checkout Session 的 URL 返回给你&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本质就是一个 &lt;strong&gt;AT → oaics_ 链接&lt;/strong&gt; 的代理服务。&lt;/p&gt;
&lt;p&gt;它的技术实现大概率是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 伪代码，非真实接口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://chatgpt.com/backend-api/payment/checkout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`Bearer &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;plus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 关键：这里可能注入了额外参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// billing_country? currency? locale?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;checkout_url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// checkout_url = &amp;#34;https://chatgpt.com/checkout/openai_llc/oaics_...&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键问题：工具只是&amp;quot;转发&amp;quot;了 AT，还是&amp;quot;动了手脚&amp;quot;？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;考虑到 PH 区有明确的 Plus 定价（约 ₱990/月），而结果是 ₱0——&lt;strong&gt;工具大概率不只是简单转发&lt;/strong&gt;。它在创建 Checkout Session 时注入了额外参数，利用跨区账号的异常处理路径绕过了服务端校验。&lt;/p&gt;
&lt;p&gt;具体注入了什么参数？没有抓包数据我们无法确定。可能是 &lt;code&gt;promotion_code&lt;/code&gt;、&lt;code&gt;discount&lt;/code&gt;、&lt;code&gt;currency&lt;/code&gt; + &lt;code&gt;amount&lt;/code&gt; 覆盖、甚至是一个 OpenAI 内部的免费试用 API 路径。但有一点可以确定：&lt;strong&gt;如果工具只是忠实转发 AT，以 PH 区 ₱990 的定价，结果不可能是 ₱0。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;工具是这个攻击链中最不透明的环节。你把 Access Token——等同于你的登录态——交给了一个第三方服务。它用你的身份做了什么请求、传了什么参数，你完全不知道。这也是为什么整个流程的&amp;quot;技术含量&amp;quot;看似很低——&lt;strong&gt;核心逻辑都藏在工具服务端里&lt;/strong&gt;，用户只是按步骤操作。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五bin-选择不是随便什么卡都行"&gt;五、BIN 选择——不是随便什么卡都行
&lt;/h2&gt;&lt;p&gt;流传的步骤里特别强调了两个 BIN：&lt;code&gt;523686&lt;/code&gt;（Mastercard）和 &lt;code&gt;4513&lt;/code&gt;（Visa）。这不是随便挑的。&lt;/p&gt;
&lt;h3 id="bin-在支付流中的角色"&gt;BIN 在支付流中的角色
&lt;/h3&gt;&lt;p&gt;BIN（Bank Identification Number）是卡号的前 6-8 位，编码了发卡行、卡网络、卡类型和发行国等信息。Stripe 在收到卡号的前 6 位时就能确定：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;523686 → Mastercard / Philippines / Credit / 某发卡行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个信息会被写入 &lt;code&gt;payment_method.card.country&lt;/code&gt;，并在整个支付流中传播。&lt;/p&gt;
&lt;h3 id="为什么必须是-ph-bin"&gt;为什么必须是 PH BIN？
&lt;/h3&gt;&lt;p&gt;PH BIN 的作用不是&amp;quot;触发一个空的价格表&amp;quot;——PH 价格表是存在的（约 ₱990/月）。&lt;/p&gt;
&lt;p&gt;更可能的解释是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;货币匹配&lt;/strong&gt;：如果工具创建的 Checkout Session 指定了 &lt;code&gt;currency: &amp;quot;php&amp;quot;&lt;/code&gt;，那么 PH 发行的卡才能让 Stripe 的 currency-card 一致性检查通过。US 卡 + PHP 货币会触发额外的风控审查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风控绕过&lt;/strong&gt;：OpenAI/Stripe 的风控系统可能对&amp;quot;card country = PH + checkout currency = PHP&amp;quot;这个组合判定为&amp;quot;正常的本地交易&amp;quot;，不会触发跨境支付的额外校验。而如果用 JP 卡或 US 卡来付一笔 0 PHP 的订单，风控更容易拦截。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AVS 绕过&lt;/strong&gt;：PH 卡不走 Stripe 的 AVS 地址校验，所以填什么地址都行——这降低了被拒的概率。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;523686 和 4513 是经过实测确认能被 Stripe 正确识别为 &lt;code&gt;card.country = &amp;quot;PH&amp;quot;&lt;/code&gt; 的 BIN 段。不是所有 PH BIN 都行，因为某些 BIN 可能已被 OpenAI/Stripe 的风控规则标记或黑名单。&lt;/p&gt;
&lt;h3 id="为什么要填美国账单地址"&gt;为什么要填美国账单地址？
&lt;/h3&gt;&lt;p&gt;这步看起来矛盾——卡是菲律宾的，地址填美国？&lt;/p&gt;
&lt;p&gt;原因是 Stripe 的 AVS（Address Verification Service）只对美国和英国的卡做地址校验。PH 卡不走 AVS，所以你填什么地址都无所谓——但如果你填 PH 地址，可能触发 OpenAI 的额外风控逻辑。填 US 地址是为了&amp;quot;看起来正常&amp;quot;，降低被风控拦截的概率。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六从防御视角看openai-需要修什么"&gt;六、从防御视角看——OpenAI 需要修什么
&lt;/h2&gt;&lt;p&gt;不管具体是哪种假说成立，防御原则是通用的。&lt;/p&gt;
&lt;h3 id="修复方案从简单到全面"&gt;修复方案（从简单到全面）
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Level 1：Checkout Session 金额校验&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_checkout_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resolve_country&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;free&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Zero-amount checkout for paid plan&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;付费产品金额为 0 时直接拒绝创建 session。这应该是支付系统的基本不变量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 3：区域一致性校验&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;resolve_country&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;registration&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;billing_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# JP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;session_ip&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;geoip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_ip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# US&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;card_bin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 创建 session 时还不知道&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 如果注册地和 session IP 不一致，以注册地为准&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 不让 card BIN 覆盖定价区域&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;signals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;registration&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定价的 country 由一个确定性函数决定，不受 card BIN 影响。Card BIN 的 country 只用于风控信号，不参与定价。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Level 4：Webhook 后置校验&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_checkout_completed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount_total&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;subscription&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 0 元订阅？不对劲&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Zero-amount subscription detected&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即使 Checkout Session 创建时金额为 0，在 &lt;code&gt;checkout.session.completed&lt;/code&gt; webhook 里也要做最终校验。这是最后一道防线。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七这个漏洞和之前的几个有什么关系"&gt;七、这个漏洞和之前的几个有什么关系？
&lt;/h2&gt;&lt;p&gt;放在一起看，这几个月被扒出来的 ChatGPT/Claude 支付漏洞其实形成了一个谱系：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;漏洞&lt;/th&gt;
 &lt;th&gt;攻击层&lt;/th&gt;
 &lt;th&gt;改了什么&lt;/th&gt;
 &lt;th&gt;核心缺陷&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/google-play-ccmax-proration-vulnerability-2026/" target="_blank" rel="noopener"
 &gt;prorationMode Hook&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;客户端内存&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;putInt&lt;/code&gt; 的一个参数&lt;/td&gt;
 &lt;td&gt;Google Play 信任客户端传入的升级策略&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/claude-cassia-mock-payment-bypass-analysis/" target="_blank" rel="noopener"
 &gt;焚决 (cassia)&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;HTTP 响应&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;checkout_flow&lt;/code&gt; 字段&lt;/td&gt;
 &lt;td&gt;前端根据 API 响应选择支付通道，后端不校验&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;RevenueCat 转移&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;聚合器 API&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;is_restore&lt;/code&gt; + &lt;code&gt;app_user_id&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;匿名购买 + restore 归属无限转移&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;API 响应注入&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;HTTP 响应&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;eligible_promo_campaigns&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;优惠码资格校验仅在前端&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;0 PHP 跨区&lt;/strong&gt; (本文)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;定价系统&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;区域信号 + 工具注入&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;跨区歧义打开异常路径 + checkout 参数校验缺失&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;注意到了吗？攻击层在不断&amp;quot;上移&amp;quot;。&lt;/p&gt;
&lt;p&gt;早期的漏洞需要 Root、需要 Frida、需要改代码——门槛不低。焚决降到了一个油猴脚本的水平。而 0 PHP 攻击&lt;strong&gt;连脚本都不需要&lt;/strong&gt;——纯操作流程，任何人都能复现。&lt;/p&gt;
&lt;p&gt;从攻击者的角度看，这是一个自然演进：&lt;strong&gt;当客户端层的防御越来越强（代码混淆、完整性校验、证书绑定），攻击者就会转向更高层——业务逻辑层、定价系统层、区域路由层。&lt;/strong&gt; 这些层的防御往往更薄弱，因为它们不像&amp;quot;加密&amp;quot;“签名&amp;quot;那样有明确的安全框架，它们是业务系统的一部分，安全评审时容易被忽略。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="八更通用的攻击模式区域信号碎片化"&gt;八、更通用的攻击模式——“区域信号碎片化”
&lt;/h2&gt;&lt;p&gt;0 PHP 攻击其实揭示了一个通用的攻击模式，我把它叫做**“区域信号碎片化攻击”（Region Signal Fragmentation）**。&lt;/p&gt;
&lt;h3 id="攻击模型"&gt;攻击模型
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;victim_system&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pricing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signal_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;registration_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="err"&gt;攻击者控制（注册时选择&lt;/span&gt; &lt;span class="n"&gt;VPN&lt;/span&gt; &lt;span class="err"&gt;节点）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signal_2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;session_ip_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="err"&gt;攻击者控制（登录时选择&lt;/span&gt; &lt;span class="n"&gt;VPN&lt;/span&gt; &lt;span class="err"&gt;节点）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signal_3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;card_bin_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="err"&gt;攻击者控制（选择特定&lt;/span&gt; &lt;span class="n"&gt;BIN&lt;/span&gt; &lt;span class="err"&gt;的卡）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signal_4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;browser_locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="err"&gt;攻击者控制（浏览器设置）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signal_5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;billing_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="err"&gt;攻击者控制（表单填写）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;所有五个信号都由攻击者完全控制。如果 &lt;code&gt;resolve()&lt;/code&gt; 函数对歧义输入的处理不当——比如进入异常分支后放松了参数校验，或者 fallback 逻辑允许客户端覆盖定价——攻击者就能把定价推入非预期状态。&lt;/p&gt;
&lt;h3 id="防御原则"&gt;防御原则
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;原则一：定价权归一&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pricing_country = user.billing_country // 只有一个来源，注册时确定
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// card BIN、IP、locale 都不参与定价决策
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 只作为风控辅助信号
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;原则二：Checkout 参数不可客户端覆盖&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 服务端决定 price、currency、amount
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 客户端/第三方传入的 discount、coupon、price_override 一律忽略
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 只接受服务端白名单内的 promotion_code，且校验账号资格
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;checkout_session = stripe.checkout.Session.create(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; line_items=[server_determined_price], # 不接受客户端 price_data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; discounts=[], # 不接受客户端 coupon
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端能影响定价 = 攻击面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原则三：零元红线&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if checkout.amount == 0 and plan.type == &amp;#34;paid&amp;#34;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; REJECT() // 无条件拒绝
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;付费产品不可能合法地出现 0 元。这应该是一个硬编码的不变量，不依赖任何业务逻辑。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="九写在最后"&gt;九、写在最后
&lt;/h2&gt;&lt;p&gt;从 prorationMode 到焚决到 RevenueCat 到 0 PHP，每一个漏洞都指向同一个结构性问题：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;当支付系统由多个独立组件（商店、聚合器、定价引擎、checkout 前端、webhook 后端）拼装而成时，组件之间的信任传递就是攻击面。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;prorationMode 的信任传递是&amp;quot;Google Play 信任客户端传入的升级策略”。焚决的信任传递是&amp;quot;前端信任 API 返回的支付通道&amp;quot;。RevenueCat 的信任传递是&amp;quot;聚合器信任 SDK 传入的 app_user_id&amp;quot;。0 PHP 的信任传递是&amp;quot;定价系统信任 card BIN 推断的国家&amp;quot;。&lt;/p&gt;
&lt;p&gt;没有一个单点漏洞，都是&lt;strong&gt;链路上的信任滑坡&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而防御的核心思路也始终一样：&lt;strong&gt;在链路的最末端（服务端 webhook、权益发放点）做最终校验，不信任链路上游传递的任何&amp;quot;结论&amp;quot;，只信任可验证的&amp;quot;事实&amp;quot;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;具体到 0 PHP 这个 case：Stripe &lt;code&gt;checkout.session.completed&lt;/code&gt; 事件里的 &lt;code&gt;amount_total&lt;/code&gt; 是事实，&lt;code&gt;currency&lt;/code&gt; 是事实。如果一个 ChatGPT Plus 订阅的 &lt;code&gt;amount_total&lt;/code&gt; 是 0——不管前面经历了多少层区域路由和定价查询——&lt;strong&gt;这就不对&lt;/strong&gt;。拦住它。&lt;/p&gt;
&lt;p&gt;这比修价格表更重要。因为价格表总有遗漏，但&amp;quot;付费产品不能 0 元&amp;quot;这条规则没有例外。&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;往期相关&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/google-play-ccmax-proration-vulnerability-2026/" target="_blank" rel="noopener"
 &gt;Google Play 内购 CC Max 漏洞深度拆解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/claude-cassia-mock-payment-bypass-analysis/" target="_blank" rel="noopener"
 &gt;焚决 Claude — 油猴脚本撬开支付大门&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;GPT Plus 订阅漏洞 — RevenueCat 凭证转移&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-google-play-subscription-transfer/" target="_blank" rel="noopener"
 &gt;GPT Plus 订阅漏洞 — Google Play Billing 鉴权缺失&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;</description></item><item><title>焚决 Claude — 一个油猴脚本如何撬开 Anthropic 的支付大门</title><link>https://blog.7qiang.com/posts/claude-cassia-mock-payment-bypass-analysis/</link><pubDate>Sun, 26 Jul 2026 04:49:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/claude-cassia-mock-payment-bypass-analysis/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post 焚决 Claude — 一个油猴脚本如何撬开 Anthropic 的支付大门" /&gt;&lt;section class="xiaoyao-contact-card" aria-label="联系逍遥"&gt;
 &lt;img class="xiaoyao-contact-card__qr" src="https://blog.7qiang.com/contact-qr.png" width="690" height="690" loading="lazy" decoding="async" alt="逍遥微信二维码"&gt;
 &lt;div class="xiaoyao-contact-card__content"&gt;
 &lt;h3 class="xiaoyao-contact-card__title"&gt;联系逍遥&lt;/h3&gt;
 &lt;p class="xiaoyao-contact-card__description"&gt;扫码添加微信，或点击下方按钮复制联系方式。&lt;/p&gt;
 &lt;div class="xiaoyao-contact-buttons" data-contact-buttons&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--wechat" type="button" data-copy-contact="plus6566" data-copy-label="微信号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;微信&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;plus6566&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;button class="xiaoyao-contact-button xiaoyao-contact-button--qq" type="button" data-copy-contact="826215906" data-copy-label="QQ 号"&gt;
 &lt;span class="xiaoyao-contact-button__label"&gt;QQ&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__value"&gt;826215906&lt;/span&gt;
 &lt;span class="xiaoyao-contact-button__status" data-copy-status&gt;点击复制&lt;/span&gt;
 &lt;/button&gt;
 &lt;span class="xiaoyao-contact-feedback" role="status" aria-live="polite"&gt;&lt;/span&gt;
&lt;/div&gt;

 &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;进微信群请联系博主，各位觉得文章对你有帮助的话可否打赏一些呀~&lt;/p&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;⚠️ 时效性提醒&lt;/strong&gt;：本文发布于 2026 年 7 月，文中涉及的 API 端点、支付流参数均为发布时有效值。Anthropic 随时可能修改 &lt;code&gt;checkout_capabilities&lt;/code&gt; 响应结构或在后端追加校验逻辑，届时本方法将失效。本文保留仅供安全研究与客户端安全防御参考。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;最近圈子里流传着一个叫**「焚决」**的东西，名字取得很玄，搞得好像什么了不得的秘术。拿到手一看——是一段不到 200 行的 Tampermonkey 油猴脚本。&lt;/p&gt;
&lt;p&gt;但别小看这 200 行代码。它干了一件非常漂亮的事情：在你打开 Claude 网页版准备付费订阅的瞬间，在浏览器内部悄无声息地篡改了一个 API 响应，把你看到的支付页面从信用卡表单换成了 SEPA 银行转账。然后你去 &lt;code&gt;randomiban.com&lt;/code&gt; 随便生成一个德国银行账号，填进去，提交——&lt;strong&gt;Claude Max 到手，扣款金额 0 元。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这玩意在外面传得沸沸扬扬，各路卡网卖的廉价 Claude 会员，相当一部分就是靠这个批量生产的。&lt;/p&gt;
&lt;p&gt;今天咱们把它彻底拆开。不光讲它怎么工作，更要讲&lt;strong&gt;为什么能成&lt;/strong&gt;、&lt;strong&gt;它利用了支付系统的哪个结构性缺陷&lt;/strong&gt;、以及&lt;strong&gt;这种攻击模式怎么迁移到其他平台&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一攻击全景一个-api-字段改写引发的连锁反应"&gt;一、攻击全景：一个 API 字段改写引发的连锁反应
&lt;/h2&gt;&lt;h3 id="正常的-claude-订阅流程"&gt;正常的 Claude 订阅流程
&lt;/h3&gt;&lt;p&gt;打开 &lt;code&gt;claude.ai&lt;/code&gt;，点击升级订阅，前端第一件事不是弹出支付表单——它先问后端一个问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GET /api/organizations/{org_id}/subscription/checkout_capabilities
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个接口的职责很简单：&lt;strong&gt;告诉前端，当前这个用户应该走哪条支付通道。&lt;/strong&gt; 后端会综合 IP 地理位置、账号注册区域、浏览器 Accept-Language 等信号，返回一个支付流标识：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checkout_flow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stripe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;前端拿到 &lt;code&gt;stripe&lt;/code&gt;，渲染信用卡表单——卡号、有效期、CVV、3DS 二次验证，一套标准流程。信用卡支付是同步授权的，银行实时校验，过不了就是过不了。&lt;/p&gt;
&lt;h3 id="劫持后的流程"&gt;劫持后的流程
&lt;/h3&gt;&lt;p&gt;脚本做的事情只有一件：&lt;strong&gt;把所有命中 &lt;code&gt;checkout_capabilities&lt;/code&gt; 的响应体替换为&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;checkout_flow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cassia&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;cassia&lt;/code&gt; 是 Anthropic 内部用于欧洲 SEPA 银行转账的支付流标识。前端一看返回值变了，渲染逻辑直接切换——不再是信用卡表单，而是一个 IBAN 输入框。&lt;/p&gt;
&lt;p&gt;这时候去 randomiban.com 生成一个德国 IBAN（格式：&lt;code&gt;DE&lt;/code&gt; + 2 位校验码 + 8 位银行代码 + 10 位账号，共 22 位），填进去，点提交。&lt;/p&gt;
&lt;p&gt;前端校验？只检查 IBAN 格式是否合法（MOD 97-10 校验通过即可）。&lt;/p&gt;
&lt;p&gt;后端校验？SEPA 体系下，&lt;strong&gt;提交时不做实时账户验证&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结果：Claude 立刻给你开通了订阅。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二sepa-直接借记为什么填个假账号也能过"&gt;二、SEPA 直接借记——为什么填个假账号也能过
&lt;/h2&gt;&lt;p&gt;这是整个攻击的核心利用点，不理解 SEPA 的清算机制，就不可能理解这个漏洞为什么成立。&lt;/p&gt;
&lt;h3 id="先搞清楚-sepa-是什么"&gt;先搞清楚 SEPA 是什么
&lt;/h3&gt;&lt;p&gt;SEPA（Single Euro Payments Area，单一欧元支付区）覆盖 36 个欧洲国家和地区，是欧盟推动的统一支付基础设施。其中的 &lt;strong&gt;SEPA Direct Debit&lt;/strong&gt;（直接借记，德语叫 Lastschriftverfahren）允许商家向消费者的银行账户&amp;quot;拉钱&amp;quot;——不是你给商家转账，而是商家拿着你的授权凭证去你的银行把钱取走。&lt;/p&gt;
&lt;p&gt;听起来很方便对吧？问题就出在这个&amp;quot;拉钱&amp;quot;的流程设计上。&lt;/p&gt;
&lt;h3 id="信用卡-vs-sepa-直接借记两套完全不同的信任模型"&gt;信用卡 vs SEPA 直接借记：两套完全不同的信任模型
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;信用卡（Stripe 标准流）&lt;/th&gt;
 &lt;th&gt;SEPA 直接借记（cassia 流）&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;授权模式&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;同步在线授权&lt;/td&gt;
 &lt;td&gt;异步离线扣款&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;交易发起时校验&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;卡号 Luhn 校验 + CVV 验证 + 3DS 二次认证 + 银行实时授权&lt;/td&gt;
 &lt;td&gt;IBAN MOD 97-10 格式校验，&lt;strong&gt;仅此而已&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;银行参与时机&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;交易发起的瞬间&lt;/td&gt;
 &lt;td&gt;交易发起后的 1-3 个工作日&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;资金确认&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;毫秒级返回授权结果&lt;/td&gt;
 &lt;td&gt;银行不返回任何确认，排队等清算&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;消费者保护&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Chargeback 争议流程&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;8 周无条件撤回权&lt;/strong&gt;（SEPA CORE 规则）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;看到关键区别了吗？信用卡在你点击支付的&lt;strong&gt;那一瞬间&lt;/strong&gt;就跟银行确认了你有没有钱、卡号对不对、你本人是不是同意的。而 SEPA 直接借记&lt;strong&gt;完全不做这些&lt;/strong&gt;——它只检查 IBAN 的格式，然后把扣款请求扔进银行间的批量清算队列里，等着慢慢处理。&lt;/p&gt;
&lt;h3 id="sepa-core-清算流程"&gt;SEPA CORE 清算流程
&lt;/h3&gt;&lt;p&gt;实际的清算过程是这样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;你提交 IBAN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;支付网关做 MOD 97-10 校验（纯数学公式，检查 IBAN 格式是否合法）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;校验通过 → 支付网关返回&amp;#34;交易成功&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Anthropic 收到成功信号 → 开通你的 Claude Max 订阅
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;... T+1 到 T+3 工作日 ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;扣款请求进入 SEPA CORE 清算系统
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;商家银行 → 消费者银行：请从账号 DEXX XXXX XXXX XXXX XXXX XX 扣 $20
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;消费者银行查询账号 → 账号不存在 / 余额不足 / 未授权
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;返回 R 代码拒绝（R02=无效账号, R04=账户已关, R05=被授权人撤销...）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Anthropic 收到扣款失败通知 → 关闭你的订阅
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;重点来了：从你提交 IBAN 到银行清算出结果，中间有一个 1-3 个工作日的真空期。&lt;/strong&gt; 在这段时间里，你的 Claude Max 订阅是完全生效的——能用 Opus、能用所有高级功能、流量不限。&lt;/p&gt;
&lt;h3 id="mod-97-10格式校验的局限性"&gt;MOD 97-10：格式校验的局限性
&lt;/h3&gt;&lt;p&gt;IBAN 的校验算法叫 ISO 7064 MOD 97-10，原理其实很简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把 IBAN 的国家代码和校验码移到末尾&lt;/li&gt;
&lt;li&gt;把字母转换为数字（A=10, B=11, …, Z=35）&lt;/li&gt;
&lt;li&gt;对整个大整数做 MOD 97 运算&lt;/li&gt;
&lt;li&gt;结果等于 1 就合法&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个算法能检出什么？&lt;strong&gt;格式错误&lt;/strong&gt;——打错了某一位、漏了一位、国家代码不对。&lt;/p&gt;
&lt;p&gt;这个算法检不出什么？&lt;strong&gt;一切跟真实世界有关的东西&lt;/strong&gt;——账户是否存在、余额是否充足、持有人是不是你。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;randomiban.com&lt;/code&gt; 生成的 IBAN 就是利用了这一点：它按照 MOD 97-10 算法逆向构造，生成的 IBAN &lt;strong&gt;格式 100% 合法&lt;/strong&gt;，能通过任何基于此算法的前端和后端校验。至于这个账号在不在现实中存在——那是 3 天后银行清算时才会发现的事情。&lt;/p&gt;
&lt;h3 id="为什么偏偏是德国-iban"&gt;为什么偏偏是德国 IBAN？
&lt;/h3&gt;&lt;p&gt;SEPA 覆盖 36 个国家，为什么脚本选了德国（DE）？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;格式最简单&lt;/strong&gt;：DE 开头的 IBAN 固定 22 位，结构是 &lt;code&gt;DE + 2位校验码 + 8位银行代码(BLZ) + 10位账号&lt;/code&gt;，没有额外的国家级校验叠加&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通过率最高&lt;/strong&gt;：德国 IBAN 在 Stripe 等主流支付网关的接受度最好，不会触发额外的地区风控&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;银行代码空间大&lt;/strong&gt;：8 位 BLZ 有大量有效的银行代码段，随机生成碰上有效 BLZ 前缀的概率不低&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对比一下法国 IBAN（27 位，还有额外的 RIB 密钥校验）或者西班牙 IBAN（24 位，有 DC 校验位），德国确实是阻力最小的选择。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三脚本逐行技术拆解"&gt;三、脚本逐行技术拆解
&lt;/h2&gt;&lt;p&gt;理解了 SEPA 的机制，再来看脚本本身就清晰多了。每一个设计决策都有明确的技术理由。&lt;/p&gt;
&lt;h3 id="31-元数据抢在一切之前"&gt;3.1 元数据——抢在一切之前
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @name TestExample Cassia Response Mock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @match *://claude.ai/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @match *://*.claude.ai/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @run-at document-start
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @grant none
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// @sandbox raw
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;三个关键设定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@run-at document-start&lt;/code&gt;&lt;/strong&gt;：页面 DOM 还没开始构建，脚本已经注入完毕。这不是可选项——如果等到 &lt;code&gt;document-idle&lt;/code&gt;，&lt;code&gt;checkout_capabilities&lt;/code&gt; 的请求可能已经发出去了，Hook 就晚了。整个攻击成立的前提就是&lt;strong&gt;比目标请求更早完成注入&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@sandbox raw&lt;/code&gt;&lt;/strong&gt;：绕过 Tampermonkey 的安全沙箱。默认沙箱会隔离脚本的执行上下文，导致你覆盖的 &lt;code&gt;window.fetch&lt;/code&gt; 和页面实际用的 &lt;code&gt;window.fetch&lt;/code&gt; 不是同一个。&lt;code&gt;raw&lt;/code&gt; 模式下脚本直接在页面上下文中执行，Hook 才能真正生效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@grant none&lt;/code&gt;&lt;/strong&gt;：不申请 &lt;code&gt;GM_*&lt;/code&gt; 系列 API 权限。一方面减少 Tampermonkey 的安全提示弹窗，另一方面 &lt;code&gt;@sandbox raw&lt;/code&gt; 本身就不兼容 &lt;code&gt;GM_*&lt;/code&gt; API。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="32-精确制导只改一个接口"&gt;3.2 精确制导——只改一个接口
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TARGET_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sr"&gt;/^\/api\/organizations\/[^/]+\/subscription\/checkout_capabilities\/?$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正则匹配精确到路径段，连末尾有没有斜杠都考虑了。&lt;strong&gt;只拦截这一个接口，其他所有请求原样放行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为什么是这个接口？因为它是 Claude 前端支付流的&lt;strong&gt;单一决策点&lt;/strong&gt;——前端根据它的返回值决定渲染 Stripe 信用卡表单还是 SEPA IBAN 输入框。控制了这个响应，就控制了用户看到的整个支付界面。&lt;/p&gt;
&lt;p&gt;这种精准度也是为了隐蔽性——如果你 Hook 了所有请求，前端的行为会出各种异常，容易暴露。只改一个接口，前端其他部分的运行完全正常。&lt;/p&gt;
&lt;h3 id="33-fetch-拦截先发后改"&gt;3.3 Fetch 拦截——先发后改
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nativeFetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getTargetUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nativeFetch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;targetUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;originalResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;createMockResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意调用顺序：&lt;strong&gt;先用原生 &lt;code&gt;fetch&lt;/code&gt; 把真实请求正常发出去，等拿到响应后再替换返回值。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是这个脚本最巧妙的地方。&lt;/p&gt;
&lt;p&gt;如果直接拦截请求不发出去，构造一个假响应返回呢？功能上没问题。但从服务端的角度看——你打开了支付页面，前端应该调 &lt;code&gt;checkout_capabilities&lt;/code&gt;，结果后端日志里根本没看到这个请求。这就是一个异常信号，可以被 Anthropic 的安全团队用于检测。&lt;/p&gt;
&lt;p&gt;先发后改的策略完美回避了这个问题：服务端日志里看到了正常的 GET 请求、正常的 200 响应，一切如常。篡改发生在浏览器内部，从 HTTPS 加密通道往外看什么都没变。&lt;/p&gt;
&lt;h3 id="34-response-重构细节决定成败"&gt;3.4 Response 重构——细节决定成败
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createMockResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content-length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content-encoding&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;etag&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content-md5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content-type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;application/json; charset=utf-8&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content-length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MOCK_LENGTH&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cache-control&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;no-store&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MOCK_BODY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;逐个分析删掉的响应头：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;content-encoding&lt;/code&gt;&lt;/strong&gt;：原始响应大概率是 gzip 或 br 压缩的。我们构造的 JSON 是明文，如果不删这个头，浏览器会拿着明文 JSON 去做 gzip 解压——直接炸。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;content-length&lt;/code&gt;&lt;/strong&gt;：原始响应体大小和我们构造的不一样，不改的话浏览器会截断或报错。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;etag&lt;/code&gt; / &lt;code&gt;content-md5&lt;/code&gt;&lt;/strong&gt;：完整性校验头。原始响应的哈希和我们篡改后的内容对不上。虽然浏览器通常不强制校验这些头，但删掉更保险——万一前端代码拿这些值做了缓存校验呢。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cache-control: no-store&lt;/code&gt;&lt;/strong&gt;：强制不缓存。如果浏览器缓存了我们的假响应，下次刷新页面不走 Hook 了就拿到缓存的假数据——反而弄巧成拙。反过来，如果缓存了之前的真响应，前端可能直接用缓存不发请求，Hook 就没机会触发。&lt;code&gt;no-store&lt;/code&gt; 确保每次都走网络请求，每次都经过 Hook。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="35-xhr-双通道保险"&gt;3.5 XHR 双通道保险
&lt;/h3&gt;&lt;p&gt;脚本不光 Hook 了 &lt;code&gt;fetch&lt;/code&gt;，还对 &lt;code&gt;XMLHttpRequest&lt;/code&gt; 做了一套完整的拦截——覆盖了 &lt;code&gt;responseText&lt;/code&gt;、&lt;code&gt;response&lt;/code&gt;、&lt;code&gt;status&lt;/code&gt;、&lt;code&gt;statusText&lt;/code&gt;、&lt;code&gt;getResponseHeader&lt;/code&gt;、&lt;code&gt;getAllResponseHeaders&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;为什么要两套？现代 Web 应用大多用 &lt;code&gt;fetch&lt;/code&gt;，但你无法保证 Anthropic 的前端代码——或者它依赖的第三方库——不会在某些场景下 fallback 到 XHR。少 Hook 一个通道就是留了一条漏网之鱼。&lt;/p&gt;
&lt;p&gt;XHR 的 Hook 方式也值得一看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;replaceXhrGetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;replacement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getOwnPropertyDescriptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;XhrPrototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;descriptor&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;function&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;configurable&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`[Cassia Mock] 无法接管 XHR.&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nativeGetter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;XhrPrototype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;getMatchedXhr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nativeGetter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;replacement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nativeGetter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用 &lt;code&gt;Object.getOwnPropertyDescriptor&lt;/code&gt; 先取原始的 property descriptor，再通过 &lt;code&gt;Object.defineProperty&lt;/code&gt; 精确替换 getter。比直接赋值靠谱得多——它保留了原始 descriptor 的所有属性（&lt;code&gt;configurable&lt;/code&gt;、&lt;code&gt;enumerable&lt;/code&gt;），而且会先检查 &lt;code&gt;configurable&lt;/code&gt; 是否为 &lt;code&gt;false&lt;/code&gt;，如果属性被冻结就优雅降级而不是静默失败。&lt;/p&gt;
&lt;h3 id="36-状态指示器"&gt;3.6 状态指示器
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;badge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;div&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cassia-mock-badge&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Cassia Mock ON&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;页面右下角一个绿色小角标，确认脚本已激活。实际攻击中这是个安慰剂——真正的确认是看支付页面有没有从信用卡变成 IBAN 输入框。但对于批量操作的卡商来说，这个视觉反馈能提高操作效率。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四横向迁移这不是一个漏洞是一类漏洞"&gt;四、横向迁移：这不是一个漏洞，是一类漏洞
&lt;/h2&gt;&lt;p&gt;分析完焚决，我们跳出来看一个更有价值的问题：&lt;strong&gt;这类攻击是可复用的。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="漏洞本质"&gt;漏洞本质
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;客户端信任边界缺失&lt;/strong&gt;：服务端将支付流的决策权——“这个用户该走哪条支付通道”——交给了一个客户端可以任意篡改的 API 响应。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这不是孤例。回顾我们之前分析过的一系列支付漏洞，它们共享同一个底层模式：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;漏洞&lt;/th&gt;
 &lt;th&gt;被篡改的对象&lt;/th&gt;
 &lt;th&gt;信任边界裂缝&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;焚决（本例）&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;checkout_capabilities&lt;/code&gt; 响应&lt;/td&gt;
 &lt;td&gt;前端信任 API 返回值决定支付通道&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GPT Plus offerToken 注入&lt;/td&gt;
 &lt;td&gt;Google Play Billing 内存中的 offerToken&lt;/td&gt;
 &lt;td&gt;服务端不校验 token 与账号资格的绑定关系&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GPT iOS 收据复用&lt;/td&gt;
 &lt;td&gt;Base64 App Store 收据&lt;/td&gt;
 &lt;td&gt;服务端不验证收据与提交者账号的对应关系&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cloudflare Pro 竞态&lt;/td&gt;
 &lt;td&gt;并发请求的状态窗口&lt;/td&gt;
 &lt;td&gt;权限发放与支付确认之间存在可利用的时序差&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;RevenueCat 回调劫持&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;fetch_token&lt;/code&gt; 跨账号提交&lt;/td&gt;
 &lt;td&gt;第三方回调接口缺乏调用方鉴权&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="通用攻击模型"&gt;通用攻击模型
&lt;/h3&gt;&lt;p&gt;把这些漏洞抽象一下，可以提取出一个四步攻击框架：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. 定位决策接口
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 找到决定支付流 / 功能开关 / 定价计算的 API 端点
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 信号关键词：checkout_capabilities, payment_methods, available_plans,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; eligible_promotions, feature_flags, entitlements
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. 注入篡改数据
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 通过油猴脚本（Web）、MITM（移动端）、Frida Hook（Native）等
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 方式替换响应内容
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. 选择确认延迟最长的路径
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SEPA 直接借记 &amp;gt; 银行转账 &amp;gt; PayPal &amp;gt; 信用卡
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 延迟越长，时间窗口越大
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. 利用&amp;#34;前端校验 + 后端真空&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 前端校验通过后，后端在异步确认完成前不暂停服务发放
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;这个框架可以复用到任何订阅制平台&lt;/strong&gt;，只要目标满足：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支付方式的选择依赖客户端可控状态&lt;/li&gt;
&lt;li&gt;存在至少一种异步确认的支付方式&lt;/li&gt;
&lt;li&gt;“服务开通&amp;quot;发生在&amp;quot;支付确认&amp;quot;之前&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在漏洞挖掘实战中，打开 DevTools Network 面板，搜索 &lt;code&gt;checkout&lt;/code&gt;、&lt;code&gt;payment&lt;/code&gt;、&lt;code&gt;billing&lt;/code&gt;、&lt;code&gt;plan&lt;/code&gt;、&lt;code&gt;subscription&lt;/code&gt; 这些关键词，找到所有影响支付逻辑的端点，逐个测试响应注入——这就是最直接的攻击面枚举方式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五防御视角"&gt;五、防御视角
&lt;/h2&gt;&lt;h3 id="给服务端开发者"&gt;给服务端开发者
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;支付流决策必须服务端闭环&lt;/strong&gt;。&lt;code&gt;checkout_flow&lt;/code&gt; 的值应该在后端根据用户地区、账号状态、风控信号独立计算，前端只是一个渲染器——它不应该有能力选择自己走哪条支付通道。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步支付必须延迟开通&lt;/strong&gt;。SEPA、银行转账这类异步支付方式，在银行返回扣款成功确认之前，不应该开通任何付费功能。可以给用户一个&amp;quot;支付处理中&amp;quot;的状态，等清算完成后再激活。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API 响应签名&lt;/strong&gt;。对关键 API 响应做 HMAC 签名（密钥存服务端），前端消费前验签。虽然不能根治（攻击者可以 Hook 验签逻辑），但大幅提高了攻击门槛——从改一个 JSON 字段变成了还得逆向验签实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IBAN 实时银行验证&lt;/strong&gt;。接入 SWIFT gpi 或各国央行的 IBAN 验证服务（如德国 Bundesbank 的 IBAN 验证接口），在提交时做实时的账户存在性校验，而不是只靠本地 MOD 97。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="给安全研究者"&gt;给安全研究者
&lt;/h3&gt;&lt;p&gt;这类漏洞的攻击面很清晰——任何一个返回了影响支付逻辑数据的 API 端点，且这个数据可以被前端篡改，都是潜在的攻击入口。&lt;/p&gt;
&lt;p&gt;一些高价值的&amp;quot;信号接口”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;checkout_capabilities&lt;/code&gt; / &lt;code&gt;payment_methods&lt;/code&gt; / &lt;code&gt;available_plans&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;region&lt;/code&gt; / &lt;code&gt;locale&lt;/code&gt; / &lt;code&gt;country_detection&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eligible_promotions&lt;/code&gt; / &lt;code&gt;offers&lt;/code&gt; / &lt;code&gt;discounts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feature_flags&lt;/code&gt; / &lt;code&gt;entitlements&lt;/code&gt; / &lt;code&gt;subscription_tiers&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="六实战翻车现场验证失败并清除旧会话"&gt;六、实战翻车现场：“验证失败并清除旧会话”
&lt;/h2&gt;&lt;p&gt;讲完了攻击原理和防御思路，再来看一个真实场景——&lt;strong&gt;焚决并不是每次都能成功的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在实际操作中（不管是焚决的 SEPA 路径还是正常的 Stripe 信用卡路径），你大概率会遇到这样一幕：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Claude支付失败截图" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;&lt;/p&gt;
&lt;p&gt;两条红色报错同时弹出来：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;“未提交付款：发生了意外错误。请检查表单后重试。”&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“验证失败并清除旧会话”&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第一次看到这个，很多人会以为是卡的问题、网络的问题、脚本的问题。其实都不是——&lt;strong&gt;这是会话状态失效的问题&lt;/strong&gt;，而且它能帮我们理解 Anthropic 的支付架构到底是怎么做验证的。&lt;/p&gt;
&lt;h3 id="为什么会出现这个错误"&gt;为什么会出现这个错误？
&lt;/h3&gt;&lt;p&gt;两条错误同时出现，意味着&lt;strong&gt;会话死在了支付提交的瞬间&lt;/strong&gt;。理解这一点需要知道 Claude 支付提交时后端做了什么：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户点击&amp;#34;提交支付&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;前端将 Stripe token / IBAN 提交到 Anthropic 后端
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;后端第一件事：校验当前会话（session）是否有效
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;会话失效 → 返回&amp;#34;验证失败&amp;#34; → 前端清除旧 session → 支付自然失败
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键点在于：Anthropic 在处理支付请求之前，会先验证你的登录会话。&lt;/strong&gt; 如果会话已经过期或被吊销，支付请求根本不会到达 Stripe——它在 session 校验这一步就被打回来了。&lt;/p&gt;
&lt;h3 id="五种常见的会话失效原因"&gt;五种常见的会话失效原因
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;① SK Cookie 过期（最常见）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude.ai 使用 &lt;code&gt;__Secure-next-auth.session-token&lt;/code&gt;（业内简称 SK Cookie）维持登录态。这个 cookie 有 TTL，通常几个小时后过期。&lt;/p&gt;
&lt;p&gt;如果你在打开支付页面之前获取的 cookie，到填完表单点提交的时候刚好过期——恭喜，踩中了时间窗口。自动化场景下尤其常见：任务在队列里排了一段时间，等轮到你的时候 cookie 已经不新鲜了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Session 被踢（多端互踢）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同一个账号如果在多个地方同时登录（比如你开了好几个 Worker 共用一个 cookie），后登录的会话会使前一个失效。你在 Worker A 上正准备提交支付，Worker B 刚好用同一个 cookie 做了一次请求刷新了 session——A 的 session 就死了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ 代理 IP 切换（Session-IP 绑定）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Anthropic 很可能在 session 上绑定了创建时的 IP 或 IP 段。如果你的代理在支付流程中间断线重连，换了一个出口 IP，后端一比对——这个 session 是从 &lt;code&gt;45.67.xx.xx&lt;/code&gt; 创建的，现在请求来自 &lt;code&gt;89.12.xx.xx&lt;/code&gt;？验证失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;④ Stripe PaymentIntent 过期&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即使 session 没问题，Stripe 侧也有自己的超时机制。&lt;code&gt;PaymentIntent&lt;/code&gt; 和对应的 &lt;code&gt;client_secret&lt;/code&gt; 有有效期（通常数小时，但在高风控场景下可能更短）。如果从打开支付页面到实际提交间隔太长，Intent 过期了，Stripe 返回错误，前端展示为&amp;quot;发生了意外错误&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⑤ Checkout Session 并发冲突&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同一个 Organization 如果同时发起了多个订阅操作（比如一个在升级 Pro，另一个在改支付方式），后一个操作创建的 &lt;code&gt;checkout session&lt;/code&gt; 会使前一个失效。前一个提交的时候引用的 session ID 已经不存在了。&lt;/p&gt;
&lt;h3 id="应对策略"&gt;应对策略
&lt;/h3&gt;&lt;p&gt;针对这类会话失效问题，无论是做自动化还是做安全防护，都有几条通用原则：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从攻击者/自动化角度看：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;策略&lt;/th&gt;
 &lt;th&gt;做法&lt;/th&gt;
 &lt;th&gt;解决的问题&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Session 预检&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;进支付页之前先调 &lt;code&gt;/api/auth/session&lt;/code&gt; 确认 cookie 存活&lt;/td&gt;
 &lt;td&gt;Cookie 过期&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;快进快出&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;打开支付页后立刻完成填写和提交，压缩停留时间&lt;/td&gt;
 &lt;td&gt;Intent 超时&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;代理钉住&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;支付全流程内锁定同一个代理出口，不允许中途切换&lt;/td&gt;
 &lt;td&gt;IP 绑定&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Cookie 生命周期管理&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;记录每个 cookie 的获取时间，临近 TTL 时主动刷新&lt;/td&gt;
 &lt;td&gt;Cookie 过期&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;错误分类重试&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;检测到&amp;quot;清除旧会话&amp;quot;后标记为 session 失效，重新获取 cookie 再试&lt;/td&gt;
 &lt;td&gt;所有会话类问题&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;单账号串行化&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;同一个 org 同时只跑一个支付操作&lt;/td&gt;
 &lt;td&gt;并发冲突&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;从防御者角度看：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个报错机制本身就是 Anthropic 的一层防线——在处理支付之前先验会话，避免在认证不确定的情况下创建订阅。这个设计是对的。&lt;/p&gt;
&lt;p&gt;但如果要更进一步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Session 绑定 + 支付确认二次绑定&lt;/strong&gt;：不光 session 绑 IP，&lt;code&gt;PaymentIntent&lt;/code&gt; 也应该绑定创建时的 session ID。Session 变了，Intent 就失效——即使攻击者拿到了一个新的有效 session，也得重新走一遍支付页面，不能复用之前的 Intent。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支付提交时的实时 Session 刷新&lt;/strong&gt;：在提交支付的瞬间，后端不仅校验 session 是否有效，还可以强制刷新一次 token，确保提交时的 session 是&amp;quot;活跃&amp;quot;的而不仅仅是&amp;quot;未过期&amp;quot;的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常模式检测&lt;/strong&gt;：如果一个 org 短时间内反复出现&amp;quot;session 校验通过 → 进入支付页 → 提交时 session 失效&amp;quot;的模式，说明有人在用自动化工具——标记为可疑行为。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="小结"&gt;小结
&lt;/h3&gt;&lt;p&gt;这个&amp;quot;验证失败&amp;quot;的报错看着烦人，但它揭示了一个重要的架构细节：&lt;strong&gt;Anthropic 的支付流不是单纯的前端-Stripe 双边交互，中间有一层 session 校验网关。&lt;/strong&gt; 这层网关既是防线（挡住了过期/伪造的会话），也是自动化场景下最常踩的坑。&lt;/p&gt;
&lt;p&gt;理解了这个机制，不管你是想加固自己平台的支付安全，还是想搞清楚为什么自己的自动化流程老是翻车——这个报错里都有答案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七写在最后"&gt;七、写在最后
&lt;/h2&gt;&lt;p&gt;焚决这个东西，技术上说穿了就是一个&lt;strong&gt;客户端状态注入&lt;/strong&gt;工具。它不攻击 Claude 的认证系统，不碰 Anthropic 的服务器，攻击目标是&lt;strong&gt;前端与后端之间那条看不见的信任边界&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它的精妙不在于代码多复杂——说真的 200 行 JS 连个正经项目的单元测试都撑不满——而在于它精准地捏住了两个系统设计缺陷的交叉点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anthropic 的前端支付流由一个可篡改的 API 响应驱动&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEPA 直接借记在清算完成前不验证账户真实性&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两个缺陷单独拿出来，各自都不算致命。但组合在一起，就变成了一条从&amp;quot;修改一个 JSON 字段&amp;quot;到&amp;quot;零元订阅 Claude Max&amp;quot;的完整攻击链。&lt;/p&gt;
&lt;p&gt;而这类&amp;quot;信任边界错位 + 异步确认间隙&amp;quot;的组合漏洞，绝不仅限于 Claude。任何一个同时提供信用卡和 SEPA 支付的 SaaS 平台，如果支付通道的选择权交给了前端，都可能面临同样的问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工具可以被修复，模式值得被记住。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="相关阅读"&gt;相关阅读
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-exploit-revenuecat-vulnerability/" target="_blank" rel="noopener"
 &gt;GPT Plus 订阅漏洞深度分析 — Google Play Billing 鉴权缺失导致 0 元订阅&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/gpt-plus-receipt-vulnerability-2026/" target="_blank" rel="noopener"
 &gt;GPT Plus 收据复用漏洞 — iOS 收据验证缺陷&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.7qiang.com/posts/manual-sec-20260519-cloudflare-billing-race-condition/" target="_blank" rel="noopener"
 &gt;Cloudflare 计费逻辑缺陷 — 请求重放绕过订阅支付&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;标签&lt;/strong&gt;: #Claude #支付安全 #API劫持 #客户端安全 #SEPA #Tampermonkey #漏洞分析 #焚决&lt;/p&gt;</description></item></channel></rss>