<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>技术分析 on 逍遥笔记</title><link>https://blog.7qiang.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90/</link><description>Recent content in 技术分析 on 逍遥笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>逍遥笔记</copyright><lastBuildDate>Sun, 16 Aug 2026 22:00:00 +0800</lastBuildDate><atom:link href="https://blog.7qiang.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90/index.xml" rel="self" type="application/rss+xml"/><item><title>Stripe 协议支付自动化深度拆解：从 HAR 抓包到纯 API 全链路实现</title><link>https://blog.7qiang.com/posts/stripe-protocol-payment-automation-deep-dive-2026/</link><pubDate>Sun, 16 Aug 2026 22:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/stripe-protocol-payment-automation-deep-dive-2026/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post Stripe 协议支付自动化深度拆解：从 HAR 抓包到纯 API 全链路实现" /&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;做过 SaaS 订阅的人都知道，Stripe 是全球最主流的支付处理商。几乎所有主流 AI 平台——从对话类到图像类——都用 Stripe 处理信用卡支付。&lt;/p&gt;
&lt;p&gt;但很少有人去研究 Stripe Checkout 背后的协议细节。大多数人的认知停留在&amp;quot;调一下 API、跳个 Checkout 页面、信用卡扣完款就行了&amp;quot;。&lt;/p&gt;
&lt;p&gt;实际上，Stripe 的 Checkout Session 协议远比你想象的复杂。从 &lt;code&gt;checkout_ui_mode&lt;/code&gt; 的 &lt;code&gt;custom&lt;/code&gt; 与 &lt;code&gt;hosted&lt;/code&gt; 两种模式，到 &lt;code&gt;ConfirmationToken&lt;/code&gt; 的创建机制，再到 &lt;code&gt;PaymentIntent&lt;/code&gt; 的 &lt;code&gt;requires_action&lt;/code&gt; 状态下 3DS 验证挑战的处理——每一步都有大量的协议细节、反欺诈检测和时序要求。&lt;/p&gt;
&lt;p&gt;今天我把这些全拆开。从 HAR 抓包出发，逐层剖析 Stripe 协议支付的完整链路，并提供 5 套不同技术栈的实现源码。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="零方法论如何逆向-stripe-支付协议"&gt;零、方法论：如何逆向 Stripe 支付协议
&lt;/h2&gt;&lt;p&gt;在开始之前，先讲方法论。所有协议支付的起点都是 &lt;strong&gt;HAR 抓包&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="01-什么是-har-文件"&gt;0.1 什么是 HAR 文件
&lt;/h3&gt;&lt;p&gt;HAR（HTTP Archive）是浏览器开发者工具导出的完整 HTTP 交互记录。包含每个请求的 URL、Headers、Body、Response，以及精确的时序信息。&lt;/p&gt;
&lt;p&gt;打开 Chrome DevTools → Network → 完成一次真实支付 → 右键 → Save all as HAR with content。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个 HAR 文件就是你的 ground truth&lt;/strong&gt;。所有协议支付的字段、值、顺序、编码方式，都以 HAR 为准。代码实现、第三方文档、安全审计报告——全部都可能过时或有误，只有 HAR 是当时浏览器真实发出的请求。&lt;/p&gt;
&lt;h3 id="02-har-分析流程"&gt;0.2 HAR 分析流程
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;筛选关键域名&lt;/strong&gt;：&lt;code&gt;api.stripe.com&lt;/code&gt;、&lt;code&gt;m.stripe.com&lt;/code&gt;、&lt;code&gt;checkout.stripe.com&lt;/code&gt;、平台 API 域名&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按时间排序&lt;/strong&gt;：找出完整的请求链路&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对比成功和失败&lt;/strong&gt;：同一流程的成功 HAR 和失败 HAR，diff 出关键差异&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提取稳定字段&lt;/strong&gt;：跨多个 HAR 都一致的值可以硬编码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标记动态字段&lt;/strong&gt;：每次不同的值（Session ID、Token、时间戳）需要运行时获取&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="03-经过验证的-har-请求链路"&gt;0.3 经过验证的 HAR 请求链路
&lt;/h3&gt;&lt;p&gt;通过分析多个成功支付的 HAR 文件，提取出标准的浏览器 Checkout 请求序列：&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. POST /api/v1/payments/checkout → 创建 session (oaics_xxx)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. GET stripe/v1/elements/sessions → 获取 Elements 配置 (deferred_intent)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. POST /api/v1/payments/checkout/taxes → 税务重算 (US免税地址可消除VAT)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. GET stripe/v1/elements/sessions → 更新后的 amount
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. POST stripe/v1/confirmation_tokens → 卡号 → ctoken_xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6. POST /api/v1/payments/checkout/confirm → 平台确认 → pi_xxx client_secret
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7. POST stripe/v1/payment_intents/{pi}/confirm → Stripe 侧扣款
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;8. GET /checkout/verify → redirect_status=succeeded
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每一步都有大量细节。下面逐一拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一为什么要做协议支付"&gt;一、为什么要做&amp;quot;协议支付&amp;quot;
&lt;/h2&gt;&lt;p&gt;先搞清楚一个概念：什么是协议支付（Protocol Payment）？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;浏览器支付&lt;/strong&gt;：用户打开 Stripe Checkout 页面 → 手动填写信用卡号 → 点击支付 → 完成。这是正常流程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;协议支付&lt;/strong&gt;：用纯 HTTP API 请求模拟浏览器的完整操作链路，包括 Stripe 的内部 API（不是官方 SDK 暴露的那些），直接在协议层完成支付，不需要浏览器。&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;：浏览器（Puppeteer/Playwright）启动慢、占内存大、不稳定；协议支付 &amp;lt;5s 完成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境隔离&lt;/strong&gt;：服务端运行，不需要 GUI 环境&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习价值&lt;/strong&gt;：深入理解支付系统的工作原理&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="二stripe-checkout-session-的两种模式"&gt;二、Stripe Checkout Session 的两种模式
&lt;/h2&gt;&lt;p&gt;Stripe Checkout 有两种 &lt;code&gt;checkout_ui_mode&lt;/code&gt;，这是整个协议支付的第一个分叉点：&lt;/p&gt;
&lt;h3 id="21-custom-模式-oaics_-前缀"&gt;2.1 Custom 模式 (&lt;code&gt;oaics_&lt;/code&gt; 前缀)
&lt;/h3&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;POST /payments/checkout
&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;checkout_ui_mode&amp;#34;: &amp;#34;custom&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;currency&amp;#34;: &amp;#34;PHP&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;plan_type&amp;#34;: &amp;#34;plus&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;→ {&amp;#34;checkout_session_id&amp;#34;: &amp;#34;oaics_xxx&amp;#34;, &amp;#34;stripe_publishable_key&amp;#34;: &amp;#34;pk_live_...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Custom 模式返回的 Session ID 以 &lt;code&gt;oaics_&lt;/code&gt; 开头。这种模式下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前端需要自己挂载 Stripe Elements&lt;/li&gt;
&lt;li&gt;通过 Stripe.js 创建 &lt;code&gt;ConfirmationToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调用平台的 &lt;code&gt;confirm&lt;/code&gt; 接口完成支付&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;直接&lt;/strong&gt;在 Stripe API 上确认 PaymentIntent&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-hosted-模式-cs_live_-前缀"&gt;2.2 Hosted 模式 (&lt;code&gt;cs_live_&lt;/code&gt; 前缀)
&lt;/h3&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;POST /payments/checkout
&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;checkout_ui_mode&amp;#34;: &amp;#34;hosted&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;currency&amp;#34;: &amp;#34;PHP&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;plan_type&amp;#34;: &amp;#34;plus&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;→ {&amp;#34;checkout_session_id&amp;#34;: &amp;#34;cs_live_xxx&amp;#34;, &amp;#34;url&amp;#34;: &amp;#34;https://checkout.stripe.com/...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hosted 模式返回 &lt;code&gt;cs_live_&lt;/code&gt; 前缀的 Session。这种模式下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stripe 托管整个 Checkout 页面&lt;/li&gt;
&lt;li&gt;走 Stripe Payment Page 的内部协议&lt;/li&gt;
&lt;li&gt;流程更复杂，涉及 &lt;code&gt;ppage_&lt;/code&gt; 初始化、&lt;code&gt;elements&lt;/code&gt; Session、&lt;code&gt;inline_confirm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要额外处理平台侧的 &lt;code&gt;approve&lt;/code&gt; 操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两种模式的选择取决于平台的 billing 配置和你的需求。一般来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果平台的计费货币与你的信用卡货币一致 → Custom 模式更简单&lt;/li&gt;
&lt;li&gt;如果存在货币不匹配（比如用美元卡付菲律宾比索订阅）→ 可能只有 Hosted 模式可用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="23-决定性参数checkout_ui_mode"&gt;2.3 决定性参数：&lt;code&gt;checkout_ui_mode&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;通过大量测试验证，&lt;strong&gt;决定返回 &lt;code&gt;oaics_&lt;/code&gt; 还是 &lt;code&gt;cs_live_&lt;/code&gt; 的唯一参数就是 &lt;code&gt;checkout_ui_mode&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="c1"&gt;// 返回 oaics_ 的请求
&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;entry_point&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;all_plans_pricing_modal&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;plan_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;basic_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="nt"&gt;&amp;#34;billing_details&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;country&amp;#34;&lt;/span&gt;&lt;span class="p"&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 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;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="nt"&gt;&amp;#34;checkout_ui_mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&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="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="c1"&gt;// 返回 cs_live_ 的请求
&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;plan_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;basic_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="nt"&gt;&amp;#34;billing_details&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;country&amp;#34;&lt;/span&gt;&lt;span class="p"&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 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;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="nt"&gt;&amp;#34;checkout_ui_mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hosted&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;cancel_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://platform.example.com/#pricing&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;locale&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;zh-CN&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;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;entry_point&lt;/code&gt;&lt;/strong&gt;：Custom 模式有，Hosted 模式没有&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cancel_url&lt;/code&gt;&lt;/strong&gt;：Hosted 模式需要（Stripe 托管页面的返回按钮用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;locale&lt;/code&gt;&lt;/strong&gt;：Hosted 模式建议传（影响 Stripe 页面语言）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hosted 模式的响应多一个 &lt;code&gt;url&lt;/code&gt; 字段——这是 Stripe 托管页面的完整 URL，可以直接在浏览器中打开。&lt;/p&gt;
&lt;h3 id="24-_stripe_version-的版本差异"&gt;2.4 &lt;code&gt;_stripe_version&lt;/code&gt; 的版本差异
&lt;/h3&gt;&lt;p&gt;这是一个极其容易忽略的细节。两种模式使用&lt;strong&gt;不同的 &lt;code&gt;_stripe_version&lt;/code&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;code&gt;_stripe_version&lt;/code&gt; 值&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Custom (oaics_)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2025-03-31.basil&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hosted (cs_live_)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2025-03-31.basil; checkout_server_update_beta=v1; checkout_manual_approval_preview=v1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Hosted 模式的版本串后面带了两个 beta flag。如果在 cs_live_ 请求中用了 Custom 的短版本串，Stripe 会返回字段缺失或行为不一致。&lt;/p&gt;
&lt;h3 id="25-两种模式的完整字段对比"&gt;2.5 两种模式的完整字段对比
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;Custom (oaics_)&lt;/th&gt;
 &lt;th&gt;Hosted (cs_live_)&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;确认端点&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;payment_intents/{pi}/confirm&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;payment_pages/{cs_live}/confirm&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;顶层 &lt;code&gt;source&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;elements&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;checkout&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;顶层 &lt;code&gt;version&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2021&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;selection_flow&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;merchant_specified&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;automatic&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;elements_session_client&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有（8 个子字段）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;elements_options_client&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;有（2 个子字段）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;link_brand&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;link&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;checkout_config_id&lt;/code&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;hCaptcha 位置&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pmd[radar_options][hcaptcha_token]&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;passive_captcha_token&lt;/code&gt;（顶层）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;init_checksum&lt;/code&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;code&gt;js_checksum&lt;/code&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;code&gt;rv_timestamp&lt;/code&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;code&gt;expected_amount&lt;/code&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;。这也是很多人协议支付做不通的原因——用了 oaics_ 的字段去调 cs_live_ 的接口，反过来也一样。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三custom-模式协议流程详解"&gt;三、Custom 模式协议流程详解
&lt;/h2&gt;&lt;p&gt;Custom 模式是最干净的协议支付路径。完整流程 8 步：&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（获取最新 Token） │
&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;│ 3. 获取定价信息（币种+金额） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 4. 创建 Checkout Session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 5. 更新税务信息（Billing 地址） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 6. 创建 ConfirmationToken（卡号→Token）│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 7. 确认支付（Confirm Checkout） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 8. 确认 PaymentIntent（Stripe 侧） │
&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;h3 id="31-创建-confirmationtoken"&gt;3.1 创建 ConfirmationToken
&lt;/h3&gt;&lt;p&gt;这是协议支付最核心的一步。浏览器里，Stripe.js 会在 iframe 中收集卡号，然后调用 Stripe 的内部 API 创建一个 &lt;code&gt;ConfirmationToken&lt;/code&gt;（&lt;code&gt;ctoken_&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-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/confirmation_tokens
&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;type=card
&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;amp;payment_method_data[type]=card
&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;amp;payment_method_data[card][number]=4242424242424242
&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;amp;payment_method_data[card][exp_month]=12
&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;amp;payment_method_data[card][exp_year]=2029
&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;amp;payment_method_data[card][cvc]=123
&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;amp;payment_method_data[billing_details][name]=John Doe
&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;amp;payment_method_data[billing_details][address][country]=US
&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;amp;payment_method_data[billing_details][address][postal_code]=97201
&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;amp;key=pk_live_xxx
&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;amp;_stripe_version=2025-03-31.basil
&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;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;key&lt;/code&gt; 必须是平台的 Stripe Publishable Key&lt;/strong&gt;，不是你自己的&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;_stripe_version&lt;/code&gt; 必须匹配&lt;/strong&gt;当前 Stripe.js 的 API 版本&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要传 Stripe.js 的指纹参数&lt;/strong&gt;：&lt;code&gt;guid&lt;/code&gt;、&lt;code&gt;muid&lt;/code&gt;、&lt;code&gt;sid&lt;/code&gt;、&lt;code&gt;time_on_page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Referer 必须是平台域名&lt;/strong&gt;，Stripe 会校验&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="卡号格式细节"&gt;卡号格式细节
&lt;/h4&gt;&lt;p&gt;HAR 验证发现，浏览器发送的卡号&lt;strong&gt;带空格&lt;/strong&gt;（&lt;code&gt;4004 1641 0185 9397&lt;/code&gt;），而不是纯数字。不过 Stripe 接受两种格式。&lt;/p&gt;
&lt;h4 id="guidmuidsid-格式"&gt;guid/muid/sid 格式
&lt;/h4&gt;&lt;p&gt;这三个指纹 ID 的格式比很多人以为的更复杂。HAR 验证的正确格式是 &lt;strong&gt;42 字符&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;guid = randomUUID() + randomHex(6)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + 6位hex
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; = 36字符UUID + 6字符 = 42字符
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;code&gt;a1b2c3d4-e5f6-4789-abcd-ef0123456789abc123&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;有些实现用 32 位纯 hex 也能工作，但 HAR 中浏览器发送的是 42 字符格式。&lt;/p&gt;
&lt;h4 id="attribution-元数据两层结构"&gt;Attribution 元数据（两层结构）
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;confirmation_tokens&lt;/code&gt; 请求中有一组 &lt;code&gt;client_attribution_metadata&lt;/code&gt; 字段，这些是 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;payment_user_agent = stripe.js/...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;client_session_id = &amp;lt;UUID&amp;gt; # 每 session 唯一
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_source = elements # ← oaics_ 固定 &amp;#34;elements&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_version = 2021
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;merchant_integration_subtype = payment-element
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;payment_intent_creation_flow = deferred
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;payment_method_selection_flow = merchant_specified # ← oaics_ 固定
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;additional_elements = [expressCheckout, payment, address]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些字段在 &lt;code&gt;confirmation_tokens&lt;/code&gt; 请求中出现两次——一次在 &lt;code&gt;payment_method_data&lt;/code&gt; 内部，一次在顶层。&lt;strong&gt;两层的值大部分相同，但 &lt;code&gt;merchant_integration_source&lt;/code&gt; 在 confirm 请求中变成 &lt;code&gt;l1&lt;/code&gt;&lt;/strong&gt;。这个细节从 HAR 中才能发现。&lt;/p&gt;
&lt;h4 id="请求头"&gt;请求头
&lt;/h4&gt;&lt;p&gt;HAR 中 Stripe 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;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept: application/json
&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;Origin: https://js.stripe.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Referer: https://js.stripe.com/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-CH-UA: &amp;#34;Not=A?Brand&amp;#34;;v=&amp;#34;99&amp;#34;, &amp;#34;Chromium&amp;#34;;v=&amp;#34;151&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;Sec-CH-UA-Mobile: ?0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-CH-UA-Platform: &amp;#34;Windows&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;Sec-Fetch-Site: same-site
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-Fetch-Mode: cors
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Sec-Fetch-Dest: empty
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;Accept-Language: en-US,en;q=0.9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意 &lt;code&gt;Accept-Language&lt;/code&gt; 必须存在。这是纯协议支付跑通的关键 bug 之一——缺少这个 header 会导致 Stripe 返回非预期的响应格式。&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;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ctoken_1xxx&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;type&amp;#34;&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;payment_method_preview&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;card&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;brand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;visa&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;last4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;4242&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;h3 id="32-确认-checkout"&gt;3.2 确认 Checkout
&lt;/h3&gt;&lt;p&gt;拿到 &lt;code&gt;ConfirmationToken&lt;/code&gt; 后，调用平台的 confirm 接口：&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 /api/v1/payments/checkout/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;{
&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_session_id&amp;#34;: &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="err"&gt; &amp;#34;confirmation_token&amp;#34;: &amp;#34;ctoken_1xxx&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;这一步平台会拿着你的 token 去 Stripe 创建 PaymentIntent 并尝试扣款。&lt;/p&gt;
&lt;p&gt;如果一切顺利（卡余额充足、无 3DS 要求），PaymentIntent 直接变成 &lt;code&gt;succeeded&lt;/code&gt;，订阅激活。&lt;/p&gt;
&lt;p&gt;如果遇到 3DS 验证，流程会更复杂——我们在第五节讲。&lt;/p&gt;
&lt;h3 id="33-elements-session--获取支付配置"&gt;3.3 Elements Session — 获取支付配置
&lt;/h3&gt;&lt;p&gt;在创建 ConfirmationToken 之前，需要先调用 Stripe 的 &lt;code&gt;elements/sessions&lt;/code&gt; API 获取支付配置信息。这一步在 HAR 中被调用&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-http" data-lang="http"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET https://api.stripe.com/v1/elements/sessions?deferred_intent[mode]=subscription
&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;amp;deferred_intent[amount]=98214
&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;amp;deferred_intent[currency]=php
&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;amp;deferred_intent[setup_future_usage]=off_session
&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;amp;deferred_intent[payment_method_types][0]=card
&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;amp;type=deferred_intent
&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;amp;key=pk_live_xxx
&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;amp;_stripe_version=2025-03-31.basil
&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;elements_session_id&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;elements_session_xxx&lt;/code&gt;，后续 confirm 请求需要&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;customer_session_client_secret&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;cuss_xxx&lt;/code&gt;，客户会话密钥&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;payment_method_configuration&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;pmc_xxx&lt;/code&gt;，支付方式配置 ID&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="34-税务地址优化--us-免税地址消除-vat"&gt;3.4 税务地址优化 — US 免税地址消除 VAT
&lt;/h3&gt;&lt;p&gt;这是一个实际操作中极其重要的技巧。&lt;/p&gt;
&lt;p&gt;很多 SaaS 平台默认按账号注册地收税。比如菲律宾区的订阅，标价 ₱982.14 但实际会加 12% VAT 变成 ₱1,100+。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：在 &lt;code&gt;taxes&lt;/code&gt; 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 /api/v1/payments/checkout/taxes
&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_session_id&amp;#34;: &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="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;name&amp;#34;: &amp;#34;John Doe&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;address&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;US&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;state&amp;#34;: &amp;#34;OR&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;city&amp;#34;: &amp;#34;Portland&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;postal_code&amp;#34;: &amp;#34;97201&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;line1&amp;#34;: &amp;#34;123 Main St&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; }
&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;美国有 5 个无销售税的州：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Oregon (OR)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Montana (MT)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delaware (DE)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New Hampshire (NH)&lt;/strong&gt; — 无销售税&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alaska (AK)&lt;/strong&gt; — 大部分地区无销售税&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HAR 验证：使用 US 地址后 tax=0，最终金额保持 ₱982.14。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重要&lt;/strong&gt;：&lt;code&gt;taxes&lt;/code&gt; 和后续 &lt;code&gt;confirmation_tokens&lt;/code&gt; 中的地址必须一致。同一个 session 内选择一个地址后全程复用。&lt;/p&gt;
&lt;h3 id="35-paymentintent-确认--stripe-侧扣款"&gt;3.5 PaymentIntent 确认 — Stripe 侧扣款
&lt;/h3&gt;&lt;p&gt;平台的 &lt;code&gt;/confirm&lt;/code&gt; 返回 &lt;code&gt;client_secret&lt;/code&gt;（格式：&lt;code&gt;pi_xxx_secret_xxx&lt;/code&gt;）后，需要调用 Stripe 的 &lt;code&gt;payment_intents/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_intents/{pi_id}/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;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;return_url = https://platform.example.com/checkout/verify?stripe_session_id=oaics_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;confirmation_token = ctoken_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;key = pk_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_secret = pi_xxx_secret_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_attribution_metadata[client_session_id] = &amp;lt;UUID&amp;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;client_attribution_metadata[merchant_integration_source] = l1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这里 &lt;code&gt;merchant_integration_source&lt;/code&gt; 变成了 &lt;code&gt;l1&lt;/code&gt;，不再是 &lt;code&gt;elements&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="pi-拒卡重试"&gt;PI 拒卡重试
&lt;/h4&gt;&lt;p&gt;HAR 验证了一个重要特性：&lt;strong&gt;同一个 PaymentIntent 被拒卡后可以用新的 ConfirmationToken 重试&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一张卡 → &lt;code&gt;generic_decline&lt;/code&gt; → PI 状态 &lt;code&gt;requires_payment_method&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;创建新的 &lt;code&gt;confirmation_token&lt;/code&gt;（用另一张卡）&lt;/li&gt;
&lt;li&gt;再次调用 &lt;code&gt;payment_intents/confirm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第二张卡 → &lt;code&gt;succeeded&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;这意味着拒卡不需要重建整个 Checkout Session&lt;/strong&gt;，只需要换卡重建 token。&lt;/p&gt;
&lt;h3 id="36-cookie-隔离架构"&gt;3.6 Cookie 隔离架构
&lt;/h3&gt;&lt;p&gt;协议支付需要严格的 Cookie 隔离。一个常见的 bug 是平台的 Cookie 被发送到 Stripe API，或反过来。&lt;/p&gt;
&lt;p&gt;最佳实践：使用两个独立的 HTTP 客户端：&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="c1"&gt;# 平台客户端 — 带 Cookie（session token）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;platform_http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies_enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&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;platform_http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;__Secure-platform-auth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session_token&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="c1"&gt;# Stripe 客户端 — 不带 Cookie&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_http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cookies_enabled&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;绝不&lt;/strong&gt;让 Stripe 客户端发送平台 Cookie，也不要让平台客户端发送 Stripe 的 Cookie。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四hosted-模式协议流程详解"&gt;四、Hosted 模式协议流程详解
&lt;/h2&gt;&lt;p&gt;Hosted 模式（&lt;code&gt;cs_live_&lt;/code&gt;）的流程更复杂，因为需要模拟 Stripe Payment Page 的完整内部协议。&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. 创建 Checkout (hosted) → cs_live_ session │
&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;│ 3. 分配信用卡 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 4. 初始化 Payment Page → ppage_ token │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 5. 获取 Elements Session │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 6. 创建 ConfirmationToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 7. 确认 Checkout (内部 confirm) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 8. 平台 Approve 操作 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 9. 轮询 PaymentIntent 状态 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 10. 处理 3DS Challenge（如果需要） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 11. 验证最终状态 │
&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;h3 id="41-payment-page-初始化"&gt;4.1 Payment Page 初始化
&lt;/h3&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;GET https://checkout.stripe.com/api/payment-page/{cs_live_xxx}/init
&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;ppage_token&amp;#34;: &amp;#34;ppage_xxx&amp;#34;, &amp;#34;merchant_name&amp;#34;: &amp;#34;...&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是 Hosted 模式独有的。返回一个 &lt;code&gt;ppage_&lt;/code&gt; token，后续所有 Stripe Payment Page API 都需要这个 token。&lt;/p&gt;
&lt;h3 id="42-elements-sessionhosted-模式特殊字段"&gt;4.2 Elements Session（Hosted 模式特殊字段）
&lt;/h3&gt;&lt;p&gt;Hosted 模式的 &lt;code&gt;elements/sessions&lt;/code&gt; 请求比 Custom 模式多出很多字段：&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/elements/sessions
&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;deferred_intent[mode] = subscription
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[amount] = 98214
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[currency] = php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[setup_future_usage] = off_session
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[payment_method_types][0] = card
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;deferred_intent[payment_method_configuration][id] = pmc_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;currency = php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;elements_init_source = custom_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;referrer_host = platform.example.com
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;stripe_js_id = &amp;lt;UUID&amp;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;locale = zh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;type = deferred_intent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;checkout_session_id = cs_live_xxx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil; checkout_server_update_beta=v1; ...
&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;code&gt;checkout_session_id&lt;/code&gt;（Custom 模式不需要）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elements_init_source&lt;/code&gt; 是 &lt;code&gt;custom_checkout&lt;/code&gt;（不是 &lt;code&gt;elements&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;需要传 &lt;code&gt;referrer_host&lt;/code&gt;、&lt;code&gt;stripe_js_id&lt;/code&gt;、&lt;code&gt;locale&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用&lt;strong&gt;长版本&lt;/strong&gt;的 &lt;code&gt;_stripe_version&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回值中有一个重要字段 &lt;code&gt;passive_captcha.rqdata&lt;/code&gt;——这是 hCaptcha Enterprise 的 &lt;code&gt;rqdata&lt;/code&gt;，后续 confirm 如果触发 challenge 需要用到。&lt;/p&gt;
&lt;h3 id="43-hosted-模式的-confirm-请求"&gt;4.3 Hosted 模式的 Confirm 请求
&lt;/h3&gt;&lt;p&gt;cs_live_ 的 confirm 走的是 &lt;code&gt;payment_pages/confirm&lt;/code&gt;，不是 &lt;code&gt;payment_intents/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/{cs_live_xxx}/confirm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个请求的 body 字段比 Custom 模式多很多：&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;elements_session_client[client_betas][0] = custom_checkout_server_updates_1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[client_betas][1] = custom_checkout_manual_approval_1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[elements_init_source] = custom_checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[referrer_host] = platform.example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[session_id] = elements_session_xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[stripe_js_id] = &amp;lt;UUID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[locale] = zh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_session_client[is_aggregation_expected] = false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_options_client[saved_payment_method][enable_save] = auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;elements_options_client[saved_payment_method][enable_redisplay] = auto
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;init_checksum = &amp;lt;checksum&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;js_checksum = &amp;lt;checksum&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rv_timestamp = &amp;lt;timestamp&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expected_amount = 98214
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;expected_payment_method_type = card
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;version = &amp;lt;build_hash&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;js_checksum&lt;/code&gt; 和 &lt;code&gt;rv_timestamp&lt;/code&gt; 是从 Stripe.js 部署状态动态提取的，&lt;code&gt;init_checksum&lt;/code&gt; 来自 init 响应。&lt;/p&gt;
&lt;h3 id="44-approve-机制与-sentinel-token"&gt;4.4 Approve 机制与 Sentinel Token
&lt;/h3&gt;&lt;p&gt;Hosted 模式下，&lt;code&gt;payment_pages/confirm&lt;/code&gt; 成功后，状态不会直接变成 &lt;code&gt;succeeded&lt;/code&gt;，而是进入 &lt;code&gt;requires_approval&lt;/code&gt;（HAR 中 confirm 返回 &lt;code&gt;status=open&lt;/code&gt;）。这时需要调用平台的 approve 接口：&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 /api/v1/payments/checkout/approve
&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 {access_token}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;X-Vendor-Challenge-Token: {sentinel_token}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="sentinel-token-结构"&gt;Sentinel Token 结构
&lt;/h4&gt;&lt;p&gt;这里的 &lt;code&gt;challenge_token&lt;/code&gt; 是一个编码后的 JSON 对象，内部包含多个通过算力证明（PoW）和 Turnstile 验证生成的字段：&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;p&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gAAAAAB...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 主负载（加密后的 PoW + session 信息）
&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;c&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="c1"&gt;// enforcement_token（基于 FNV-1a 的算力证明结果）
&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;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;UUID&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&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; &lt;span class="nt"&gt;&amp;#34;flow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;platform_checkout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&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; &lt;span class="nt"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;turnstile_dx_token&amp;gt;&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;// 4000+ 字符的 Turnstile 验证 token
&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;t&lt;/code&gt; 字段是核心&lt;/strong&gt;——如果为空字符串，approve 立即返回 &lt;code&gt;blocked&lt;/code&gt;。它来自 Cloudflare Turnstile 的隐式挑战验证（不是肉眼可见的验证码）。&lt;/p&gt;
&lt;h4 id="sentinel-token-生成流程"&gt;Sentinel Token 生成流程
&lt;/h4&gt;&lt;p&gt;完整的 Sentinel 生成需要两个组件协作：&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. 生成 requirements_token（本地 seed + difficulty &amp;#34;0&amp;#34;）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. POST sentinel.platform.com/backend-api/sentinel/req
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 返回 {turnstile: {dx: &amp;#34;...&amp;#34;}, ...}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. 用 server seed 生成 enforcement_token（FNV-1a 算力证明）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. 在 Node.js VM 中执行 Turnstile SDK（需要 jsdom 模拟 DOM 环境）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 返回 turnstile token（~4388 字符）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. 组装 JSON → Base64 → 设为请求头
&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;PoW 使用 &lt;strong&gt;FNV-1a&lt;/strong&gt; 哈希算法，difficulty 对 checkout 流程通常是 “0”（即几乎不需要算力）&lt;/li&gt;
&lt;li&gt;Turnstile SDK 必须在&lt;strong&gt;真实的 DOM 环境&lt;/strong&gt;中执行——简单的字符串拼接无法通过验证&lt;/li&gt;
&lt;li&gt;实际生产中需要 Node.js + jsdom 来执行官方 Turnstile VM&lt;/li&gt;
&lt;li&gt;SDK 代码需要定期更新（随平台版本迭代）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="approve-的正确时机"&gt;Approve 的正确时机
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;关键发现&lt;/strong&gt;：Approve 不应该主动调用。正确的流程是 &lt;strong&gt;fall-through&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;confirm → status=open, requires_approval
&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 回调
&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; 平台自动完成 approve（不需要客户端调）
&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; poll payment_page → PI 出现
&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; 可能 requires_action → verify_challenge
&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; poll 到 succeeded → 完成
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但某些边缘情况下（平台回调未触发），客户端需要手动 approve。此时 Sentinel token 是必须的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Approve 是&lt;strong&gt;一次性操作&lt;/strong&gt;，同一 session 不可重复&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;t&lt;/code&gt; 字段为空或格式错误 → 返回 &lt;code&gt;blocked&lt;/code&gt; → session 作废&lt;/li&gt;
&lt;li&gt;成功的 approve 返回 &lt;code&gt;{&amp;quot;result&amp;quot;:&amp;quot;approved&amp;quot;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="五3ds-验证挑战"&gt;五、3DS 验证挑战
&lt;/h2&gt;&lt;p&gt;当 Stripe 判断交易需要额外验证时，PaymentIntent 会进入 &lt;code&gt;requires_action&lt;/code&gt; 状态，附带 3DS challenge 信息。&lt;/p&gt;
&lt;h3 id="51-challenge-类型"&gt;5.1 Challenge 类型
&lt;/h3&gt;&lt;p&gt;Stripe 使用 hCaptcha Enterprise 作为 3DS 验证手段：&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;verify_with_challenge&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;verify_with_challenge&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://challenges.stripe.com/...&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;challenge_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;hcaptcha&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;h3 id="52-verify_challenge-完整请求格式"&gt;5.2 verify_challenge 完整请求格式
&lt;/h3&gt;&lt;p&gt;HAR 中验证的 &lt;code&gt;verify_challenge&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_intents/{pi_id}/verify_challenge
&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;captcha_response = {hcaptcha_token} # P0开头的长字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;captcha_vendor_name = hcaptcha # 固定值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;captcha_sitekey = xxxxxxxx-xxxx-xxxx # Stripe 的 hCaptcha sitekey
&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_amount = 98214 # 交易金额
&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_currency = php # 币种
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;key = pk_live_xxx # Publishable Key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;_stripe_version = 2025-03-31.basil; checkout_server_update_beta=v1; ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;client_secret = pi_xxx_secret_xxx # PI 的 client_secret
&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;code&gt;captcha_response&lt;/code&gt; 而不是 &lt;code&gt;challenge_response&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要同时传 &lt;code&gt;captcha_vendor_name&lt;/code&gt; 和 &lt;code&gt;captcha_sitekey&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;需要传 &lt;code&gt;expected_amount&lt;/code&gt;/&lt;code&gt;expected_currency&lt;/code&gt; 做一致性校验&lt;/li&gt;
&lt;li&gt;使用&lt;strong&gt;长版本&lt;/strong&gt; &lt;code&gt;_stripe_version&lt;/code&gt;（与 Hosted 模式一致）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="53-hcaptcha-enterprise-的特殊性"&gt;5.3 hCaptcha Enterprise 的特殊性
&lt;/h3&gt;&lt;p&gt;Stripe 使用的不是普通 hCaptcha，而是 &lt;strong&gt;hCaptcha Enterprise&lt;/strong&gt;。区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;有 &lt;code&gt;rqdata&lt;/code&gt; 参数&lt;/strong&gt;：普通 hCaptcha 不需要 rqdata，Enterprise 必须传&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sitekey 是 Stripe 专有的&lt;/strong&gt;：从 &lt;code&gt;elements/sessions&lt;/code&gt; 响应的 &lt;code&gt;passive_captcha&lt;/code&gt; 字段中提取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;invisible 模式&lt;/strong&gt;：浏览器里看不到验证码图片，但后台在做风控评估&lt;/li&gt;
&lt;/ol&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="c1"&gt;# 从 elements_session 响应中提取&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rqdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements_session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;passive_captcha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rqdata&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="n"&gt;sitekey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements_session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;passive_captcha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sitekey&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;h3 id="54-时效性问题"&gt;5.4 时效性问题
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;hCaptcha token 有时效性&lt;/strong&gt;——浏览器里 ~4 秒解出即有效，但远程打码服务可能需要 30-120 秒。如果超时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;verify_challenge&lt;/code&gt; 返回 &lt;code&gt;payment_intent_authentication_failure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;但 PI 状态仍然是 &lt;code&gt;requires_action&lt;/code&gt;——&lt;strong&gt;可以重新 verify_challenge&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决方案分级：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;最优&lt;/strong&gt;：本地 headless 浏览器解 hCaptcha（&amp;lt;5s，成功率 95%+）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;次优&lt;/strong&gt;：支持 Enterprise rqdata 的快速打码 API（如 YesCaptcha，~15s）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兜底&lt;/strong&gt;：如果 PI 已经进入 &lt;code&gt;requires_action&lt;/code&gt;，可以循环重试 verify_challenge（每次用新 captcha token）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="55-3ds-vs-hcaptcha-的区别"&gt;5.5 3DS vs hCaptcha 的区别
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;重要澄清&lt;/strong&gt;：Stripe 的 &lt;code&gt;verify_with_challenge&lt;/code&gt; 并非传统银行 3DS 验证（3D Secure）。它是 Stripe 自有的风控挑战，使用 hCaptcha 作为人机验证手段。&lt;/p&gt;
&lt;p&gt;真正的银行 3DS（如 Visa Secure）会打开银行页面要求输入 OTP/密码，这个在纯协议支付中&lt;strong&gt;无法绕过&lt;/strong&gt;——但使用虚拟信用卡（VCC）通常不会触发银行 3DS，只会触发 Stripe 自身的 hCaptcha challenge。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六tls-指纹对抗"&gt;六、TLS 指纹对抗
&lt;/h2&gt;&lt;p&gt;纯 HTTP 请求最大的挑战不是协议逻辑，而是 &lt;strong&gt;TLS 指纹&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Stripe 和 Cloudflare 都会检查 TLS Client Hello 的指纹（JA3/JA4），如果发现你的 TLS 握手特征不像浏览器，直接返回 403/429。&lt;/p&gt;
&lt;h3 id="61-指纹伪装"&gt;6.1 指纹伪装
&lt;/h3&gt;&lt;p&gt;Python 项目使用 &lt;code&gt;curl_cffi&lt;/code&gt; 库，支持模拟多种浏览器的 TLS 指纹：&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="n"&gt;PROFILES&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="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chrome131&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Chrome/131.0&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 class="s2"&gt;&amp;#34;chrome124&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Chrome/124.0&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 class="s2"&gt;&amp;#34;safari18&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Safari/605.1&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 class="s2"&gt;&amp;#34;firefox117&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 ... Firefox/117.0&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;Node.js 项目使用 &lt;code&gt;CycleTLS&lt;/code&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="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;initCycleTLS&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cycletls&amp;#39;&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;cycleTLS&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;initCycleTLS&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;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;cycleTLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;ja3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;771,4865-4866-4867...&amp;#39;&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;userAgent&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Mozilla/5.0 ...&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="62-指纹轮换策略"&gt;6.2 指纹轮换策略
&lt;/h3&gt;&lt;p&gt;当遇到 403/429 时，自动切换到下一个 TLS 指纹配置：&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;class&lt;/span&gt; &lt;span class="nc"&gt;TLSFingerprintManager&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;def&lt;/span&gt; &lt;span class="nf"&gt;rotate_on_failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exclude_current&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pick_next&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;最多重试 3 次，每次使用不同的浏览器指纹。&lt;/p&gt;
&lt;h3 id="63-tls-指纹与-user-agent-一致性"&gt;6.3 TLS 指纹与 User-Agent 一致性
&lt;/h3&gt;&lt;p&gt;一个常见错误是 TLS 指纹和 User-Agent 不匹配。比如用 Chrome 131 的 TLS 指纹配置但 User-Agent 写的是 Chrome 124，Cloudflare 的 bot detection 会立即发现这种不一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正确做法&lt;/strong&gt;：TLS profile 和 UA 必须成对配置：&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="n"&gt;PROFILES&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="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;tls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;chrome131&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="s2"&gt;&amp;#34;ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/131.0.0.0 Safari/537.36&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="s2"&gt;&amp;#34;sec_ch_ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#34;Not=A?Brand&amp;#34;;v=&amp;#34;99&amp;#34;, &amp;#34;Chromium&amp;#34;;v=&amp;#34;131&amp;#34;&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="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;tls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;safari18&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="s2"&gt;&amp;#34;ua&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) ... Safari/605.1.15&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="s2"&gt;&amp;#34;sec_ch_ua&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="c1"&gt;# Safari 不发 sec-ch-ua&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;h3 id="64-http-协议版本"&gt;6.4 HTTP 协议版本
&lt;/h3&gt;&lt;p&gt;另一个细节：Stripe 的 API 请求在浏览器中走 &lt;strong&gt;HTTP/2&lt;/strong&gt;，但 &lt;code&gt;payment_intents/confirm&lt;/code&gt; 在某些实现中用 HTTP/1.1 反而更稳定。&lt;/p&gt;
&lt;p&gt;HAR 中观察到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;confirmation_tokens&lt;/code&gt;：HTTP/2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment_intents/confirm&lt;/code&gt;：可以 HTTP/1.1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment_pages/confirm&lt;/code&gt;：HTTP/2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 &lt;code&gt;curl_cffi&lt;/code&gt; 时默认走 HTTP/2（如果服务端支持），CycleTLS 需要在选项中显式指定。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七stripejs-指纹参数"&gt;七、Stripe.js 指纹参数
&lt;/h2&gt;&lt;p&gt;Stripe 的 &lt;code&gt;confirmation_tokens&lt;/code&gt; 和 &lt;code&gt;payment_intents/confirm&lt;/code&gt; 接口都需要一组指纹参数。这些参数由 Stripe.js 在前端收集，协议支付需要正确模拟：&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;guid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;全局唯一 ID&lt;/td&gt;
 &lt;td&gt;UUID + 6位 hex = 42 字符（见 3.1 节）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;muid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;设备 ID&lt;/td&gt;
 &lt;td&gt;同 guid 格式，42 字符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;会话 ID&lt;/td&gt;
 &lt;td&gt;同 guid 格式，42 字符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;time_on_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;页面停留时间&lt;/td&gt;
 &lt;td&gt;随机 8-30 秒（模拟真实用户）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;key&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Publishable Key&lt;/td&gt;
 &lt;td&gt;从 Checkout Session 获取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;_stripe_version&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;API 版本&lt;/td&gt;
 &lt;td&gt;从 Stripe.js 的 basil 部署中提取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="71-mstripecom6--指纹注册"&gt;7.1 m.stripe.com/6 — 指纹注册
&lt;/h3&gt;&lt;p&gt;在所有业务请求之前，Stripe.js 会向 &lt;code&gt;m.stripe.com/6&lt;/code&gt; 发送 4 次 POST 请求注册设备指纹。HAR 中的完整调用链：&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;POST https://m.stripe.com/6 (×4)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次请求的 body 是 &lt;code&gt;application/x-www-form-urlencoded&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;v2 = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id = &amp;lt;stripe_js_id&amp;gt; # 与 confirmation_tokens 中的 guid 不同
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tag = &amp;lt;event_tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;src = js
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a = &amp;lt;JSON编码的分析数据&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tag&lt;/code&gt; 的值依次为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;stripejs-init-started&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stripejs-init-complete&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adyen-component-loaded&lt;/code&gt;（如果有 Adyen）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment-element-mounted&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;a&lt;/code&gt; 字段包含浏览器环境的详细指纹数据（屏幕尺寸、时区、语言、plugin 列表等）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实际影响&lt;/strong&gt;：不发这些请求也能支付成功，但长期使用同一个 &lt;code&gt;guid&lt;/code&gt;/&lt;code&gt;muid&lt;/code&gt; 而从未注册过指纹可能触发 Stripe Radar 的异常检测。建议至少发一次 &lt;code&gt;stripejs-init-complete&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="72-rstripecomb--遥测上报"&gt;7.2 r.stripe.com/b — 遥测上报
&lt;/h3&gt;&lt;p&gt;Stripe.js 还会持续向 &lt;code&gt;r.stripe.com/b&lt;/code&gt; 发送遥测数据：&lt;/p&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;POST&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;plain&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt; &lt;span class="n"&gt;payload&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;这个请求的 payload 是 JSON（不是 form-urlencoded），包含支付流程中的各种事件指标（加载时间、渲染时间、错误数）。&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;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;measurement&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;event_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;paymentElement.mount&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;metrics&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;duration&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;342&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;client_session_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;UUID&amp;gt;&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;publish_key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pk_live_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;strong&gt;实际影响&lt;/strong&gt;：纯可选。不发不影响支付成功。但如果你的实现在生产中运行，偶尔发几次遥测可以让你的流量看起来更像真实浏览器。&lt;/p&gt;
&lt;h3 id="73-动态提取-stripejs-版本"&gt;7.3 动态提取 Stripe.js 版本
&lt;/h3&gt;&lt;p&gt;Stripe.js 的版本（&lt;code&gt;_stripe_version&lt;/code&gt;）和构建哈希（&lt;code&gt;rv&lt;/code&gt;/&lt;code&gt;sv&lt;/code&gt;）不是固定的，需要从 Stripe 的部署状态接口动态提取：&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;// 获取当前 Stripe.js 部署信息
&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;status&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="s1"&gt;&amp;#39;https://js.stripe.com/deploy_status_henson.json&amp;#39;&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;basil&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;status&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;// basil.rv = &amp;#34;2025-03-31&amp;#34; → _stripe_version = &amp;#34;2025-03-31.basil&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Custom 模式只需要基础版本：&lt;code&gt;2025-03-31.basil&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Hosted 模式需要追加 beta flags：&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;2025-03-31.basil; checkout_server_update_beta=v1; custom_checkout_beta=v1; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些 beta flags 从 &lt;code&gt;deploy_status_henson.json&lt;/code&gt; 的 metadata 或 checkout 页面的初始化脚本中提取。Stripe 大约每 1-2 周更新一次部署版本。&lt;/p&gt;
&lt;h3 id="74-js_checksum-和-rv_timestamp"&gt;7.4 js_checksum 和 rv_timestamp
&lt;/h3&gt;&lt;p&gt;Hosted 模式的 &lt;code&gt;payment_pages/confirm&lt;/code&gt; 需要两个动态校验值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;js_checksum&lt;/code&gt;&lt;/strong&gt;：当前 Stripe.js bundle 的 SHA 校验和，从 deploy status 提取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rv_timestamp&lt;/code&gt;&lt;/strong&gt;：当前 Stripe.js 的部署时间戳（Unix 毫秒），也从 deploy status 提取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两个值随 Stripe.js 版本更新而变化。如果使用过期的 checksum/timestamp，confirm 可能会被静默拒绝。&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="n"&gt;deploy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://js.stripe.com/deploy_status_henson.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&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="n"&gt;js_checksum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;basil&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;js_checksum&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="n"&gt;rv_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;basil&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rv_timestamp&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;hr&gt;
&lt;h2 id="八代理池架构"&gt;八、代理池架构
&lt;/h2&gt;&lt;p&gt;协议支付的另一个核心组件是代理池。Stripe 和平台都会检查请求的源 IP，用数据中心 IP 直连容易被标记。&lt;/p&gt;
&lt;h3 id="81-双代理池"&gt;8.1 双代理池
&lt;/h3&gt;&lt;p&gt;最佳实践是使用两个独立的代理池：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;平台代理池&lt;/strong&gt;：用于访问 SaaS 平台的 API（需要与账号注册地匹配）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stripe 代理池&lt;/strong&gt;：用于访问 Stripe API（需要住宅 IP，避免被 Radar 标记）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="82-代理健康检查"&gt;8.2 代理健康检查
&lt;/h3&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;class&lt;/span&gt; &lt;span class="nc"&gt;ProxyVerifier&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;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected_country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://ipapi.co/json/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;proxy_url&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;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;country_code&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;if&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected_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 class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ProxyCountryMismatchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&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;h3 id="83-出口-ip-一致性"&gt;8.3 出口 IP 一致性
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;关键规则&lt;/strong&gt;：创建 Checkout Session 和确认支付时，必须使用&lt;strong&gt;同一个出口 IP&lt;/strong&gt;。Stripe 会比对两次请求的 IP，如果不一致会拒绝交易。&lt;/p&gt;
&lt;p&gt;这意味着整个支付流程中的所有请求（从创建 session 到 confirm）必须绑定同一个代理出口。如果代理池做了负载均衡，需要在支付流程中&amp;quot;钉住&amp;quot;一个代理节点。&lt;/p&gt;
&lt;h3 id="84-代理类型选择"&gt;8.4 代理类型选择
&lt;/h3&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;住宅代理（Residential）&lt;/td&gt;
 &lt;td&gt;Stripe API / 平台 API&lt;/td&gt;
 &lt;td&gt;最安全，IP 信誉高&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ISP 代理（Static Residential）&lt;/td&gt;
 &lt;td&gt;长期固定使用&lt;/td&gt;
 &lt;td&gt;中等，某些已被标记&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;数据中心代理（Datacenter）&lt;/td&gt;
 &lt;td&gt;测试/开发&lt;/td&gt;
 &lt;td&gt;高风险，Stripe Radar 会标记&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;移动代理（Mobile）&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;生产环境建议住宅代理。数据中心 IP 在 Stripe 的风控系统中通常有较高的 risk score。&lt;/p&gt;
&lt;h3 id="85-代理故障降级"&gt;8.5 代理故障降级
&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-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_proxy_with_fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&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 class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&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 class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proxy&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="n"&gt;proxy&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="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;US&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;if&lt;/span&gt; &lt;span class="n"&gt;proxy&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="n"&gt;proxy&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow_direct&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="kc"&gt;None&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="n"&gt;NoProxyAvailableError&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;：不要在生产环境用直连降级——数据中心 IP 直连 Stripe 几乎必被拒。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="九状态机设计"&gt;九、状态机设计
&lt;/h2&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;初始化 → 刷新Session → 检查权限 → 获取定价 → 创建Checkout
&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; 更新税务 → 创建Token → 确认支付
&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; 失败→退出 卡被拒→换卡 3DS→验证
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个状态转移都需要处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;卡被拒（Card Declined）&lt;/strong&gt;：分类拒绝原因（余额不足/CVV错误/风控拒绝），决定是换卡重试还是放弃&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3DS 验证&lt;/strong&gt;：进入 Challenge 流程&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session 过期&lt;/strong&gt;：创建新 Session 重试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate Limiting&lt;/strong&gt;：TLS 指纹轮换 + 退避重试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="91-decline-错误分类"&gt;9.1 Decline 错误分类
&lt;/h3&gt;&lt;p&gt;Stripe 的卡拒绝错误不是一个笼统的&amp;quot;失败&amp;quot;，而是分为可重试和不可重试两类：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可重试（换卡后重试）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;generic_decline&lt;/code&gt; — 最常见，通常是风控拒绝，换卡几乎总能过&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insufficient_funds&lt;/code&gt; — 余额不足，充值后或换卡可过&lt;/li&gt;
&lt;li&gt;&lt;code&gt;processing_error&lt;/code&gt; — Stripe 侧临时错误，直接重试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;不可重试（放弃本次 session）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stolen_card&lt;/code&gt; / &lt;code&gt;lost_card&lt;/code&gt; — 卡已被标记，不能再用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;card_not_supported&lt;/code&gt; — 卡类型不支持（如某些预付卡）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currency_not_supported&lt;/code&gt; — 卡不支持目标币种&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;需要特殊处理&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;incorrect_cvc&lt;/code&gt; — CVC 错误，检查是否传错了&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expired_card&lt;/code&gt; — 卡过期，需要从卡池中移除&lt;/li&gt;
&lt;li&gt;&lt;code&gt;card_velocity_exceeded&lt;/code&gt; — 卡的交易频率超限，冷却后可重试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="92-fast-path-优化"&gt;9.2 Fast-Path 优化
&lt;/h3&gt;&lt;p&gt;一个重要的状态机优化：&lt;strong&gt;如果 PI 已经 &lt;code&gt;succeeded&lt;/code&gt;，跳过 hCaptcha&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;HAR 中发现，有时 confirm 返回 &lt;code&gt;requires_action&lt;/code&gt;（hCaptcha challenge），但 PI 实际上已经扣款成功。这时如果盲目去解 captcha，反而可能出错。&lt;/p&gt;
&lt;p&gt;正确做法是在收到 &lt;code&gt;requires_action&lt;/code&gt; 后，&lt;strong&gt;先查询 PI 状态&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="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/v1/payment_intents/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pi_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pk_live&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;pi&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;succeeded&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;# 已经扣款成功，跳过 captcha&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;PaymentResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="c1"&gt;# 确实需要解 captcha&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;solve_hcaptcha&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi&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;h3 id="93-hosted-模式轮询"&gt;9.3 Hosted 模式轮询
&lt;/h3&gt;&lt;p&gt;cs_live_ 模式在 confirm 之后需要轮询 &lt;code&gt;payment_page&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;POST https://api.stripe.com/v1/payment_pages/{cs_live_xxx}/poll
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;status&amp;#34;: &amp;#34;open&amp;#34;} // 等待中
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;payment_object_status&amp;#34;: &amp;#34;requires_action&amp;#34;} // 需要 captcha
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;→ {&amp;#34;payment_intent&amp;#34;: &amp;#34;pi_xxx&amp;#34;, &amp;#34;payment_object_status&amp;#34;: &amp;#34;succeeded&amp;#34;} // 完成
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;轮询间隔建议 2-3 秒，最多轮询 60 秒。如果超时未变化，检查是否需要手动 approve。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="十安全边界与最佳实践"&gt;十、安全边界与最佳实践
&lt;/h2&gt;&lt;h3 id="101-session-隔离"&gt;10.1 Session 隔离
&lt;/h3&gt;&lt;p&gt;每次支付使用独立的 Session，不复用已失败的 Session。特别是 Hosted 模式下，&lt;code&gt;approve&lt;/code&gt; 操作后的 Session 不可再次使用。&lt;/p&gt;
&lt;h3 id="102-dry-run-模式"&gt;10.2 Dry-Run 模式
&lt;/h3&gt;&lt;p&gt;所有实现都应支持 Dry-Run 模式——执行完整流程但不提交最终的 &lt;code&gt;confirm&lt;/code&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;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit_payments&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confirm_payment_intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pi_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&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;else&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;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Dry-run: skipping confirm&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;这对于调试非常重要：你可以验证整个流程（创建 session、生成 token、税务计算）都正确，而不实际扣钱。&lt;/p&gt;
&lt;h3 id="103-不要存储敏感数据"&gt;10.3 不要存储敏感数据
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;信用卡号仅在内存中使用，支付完成后立即清除&lt;/li&gt;
&lt;li&gt;Session token 不应写入日志（log 中用 &lt;code&gt;***&lt;/code&gt; 替代）&lt;/li&gt;
&lt;li&gt;代理凭据不要硬编码，用环境变量或加密存储&lt;/li&gt;
&lt;li&gt;Stripe Publishable Key 可以写入代码（它本来就是公开的），但 Secret Key 绝不能出现在客户端&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="104-请求节奏模拟"&gt;10.4 请求节奏模拟
&lt;/h3&gt;&lt;p&gt;纯协议支付的一个风险是请求速度&lt;strong&gt;太快&lt;/strong&gt;。浏览器用户从打开支付页面到点击确认，通常需要 15-60 秒。如果你的自动化在 2 秒内完成全部请求，Stripe Radar 可能标记为异常。&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-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&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="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;))&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;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 创建 token 后&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# confirm 前&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总时间控制在 8-30 秒之间比较自然。&lt;/p&gt;
&lt;h3 id="105-并发控制"&gt;10.5 并发控制
&lt;/h3&gt;&lt;p&gt;批量处理多个账号时，不要让所有请求同时发出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stripe API&lt;/strong&gt;：有 rate limit，同一 publishable key 下大量并发 confirm 会触发 429&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台 API&lt;/strong&gt;：多个账号同时操作可能触发风控&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代理池&lt;/strong&gt;：每个代理 IP 上同时只运行 1-2 个支付流程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议使用信号量（semaphore）限制并发：&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="n"&gt;sem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Semaphore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 最多同时处理 3 个支付&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;sem&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;await&lt;/span&gt; &lt;span class="n"&gt;process_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&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;hr&gt;
&lt;h2 id="十一实现对比"&gt;十一、实现对比
&lt;/h2&gt;&lt;p&gt;文末提供的 5 套实现覆盖了不同的技术栈和使用场景：&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;strong&gt;saas-pay-sdk&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python / CLI&lt;/td&gt;
 &lt;td&gt;Custom&lt;/td&gt;
 &lt;td&gt;最精简的 CLI 工具，TLS 指纹轮换，daemon 上报&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;subscription-manager&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python Flask / Web UI&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;完整 Web 管理面板，支持绑卡、查账单、升级降级&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;payment-gateway&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python Flask / Web UI&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;批量支付面板，账号池管理，barrier 模式批量确认&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;checkout-server&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Python / Local HTTP&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;本地支付编排服务器，Playwright 降级，SQLite 持久化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;protocol-engine&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Node.js / Modules&lt;/td&gt;
 &lt;td&gt;Both&lt;/td&gt;
 &lt;td&gt;模块化协议引擎，CycleTLS，动态 Stripe.js 版本抓取&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;每个实现都有自己的优缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;想要最快上手 → &lt;code&gt;saas-pay-sdk&lt;/code&gt;（纯 CLI，pip install 即可）&lt;/li&gt;
&lt;li&gt;想要可视化管理 → &lt;code&gt;subscription-manager&lt;/code&gt;（Web UI）&lt;/li&gt;
&lt;li&gt;想要批量处理 → &lt;code&gt;payment-gateway&lt;/code&gt;（账号池 + 批量模式）&lt;/li&gt;
&lt;li&gt;想要理解底层 → &lt;code&gt;protocol-engine&lt;/code&gt;（模块化，可以单独引用任何一层）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="下载"&gt;下载
&lt;/h2&gt;&lt;p&gt;以下是 5 套完整实现的源码下载链接：&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;saas-pay-sdk&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/saas-pay-sdk.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Python CLI 工具&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;subscription-manager&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/subscription-manager.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Flask Web 管理面板&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;payment-gateway&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/payment-gateway.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;批量支付网关面板&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;checkout-server&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/checkout-server.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;本地支付编排服务器&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;protocol-engine&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="https://blog.7qiang.com/downloads/protocol-engine.zip" &gt;下载&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Node.js 协议引擎模块&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：所有源码中的 API Key、域名、账号信息均已替换为占位符。使用前需要根据你的实际环境配置 &lt;code&gt;.env&lt;/code&gt; 文件。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="推荐虚拟卡平台"&gt;推荐：虚拟卡平台
&lt;/h2&gt;&lt;p&gt;协议支付离不开信用卡。如果你需要一张支持 Stripe 的虚拟信用卡用于订阅海外 SaaS 服务（ChatGPT、Claude、Cursor 等），推荐 &lt;strong&gt;ZovoCard&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持 Visa / Mastercard，全球 Stripe 商户可用&lt;/li&gt;
&lt;li&gt;即开即用，无需实体卡，支持 USDT 充值&lt;/li&gt;
&lt;li&gt;多卡管理，适合批量订阅场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="link" href="https://zovocard.com/register?invite=DW6AYPAP" target="_blank" rel="noopener"
 &gt;注册 ZovoCard →&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你对支付安全感兴趣，欢迎加微信群交流。&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Gmail Sanitizer 深度拆解：8 步全链路凭据切断的自动化实现</title><link>https://blog.7qiang.com/posts/gmail-sanitizer-credential-cutoff-analysis/</link><pubDate>Tue, 04 Aug 2026 14:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/gmail-sanitizer-credential-cutoff-analysis/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post Gmail Sanitizer 深度拆解：8 步全链路凭据切断的自动化实现" /&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;：Gmail Sanitizer 不是简单的&amp;quot;改密码工具&amp;quot;，而是一套 8 步全链路凭据切断系统——从恢复邮箱、恢复手机、Passkey、2FA 密钥到 OAuth 授权，把卖家在账号上留下的所有后门逐一切断，最后用新凭据重新登录验证。底层用 DrissionPage 驱动真实 Chrome 绕过 Google 反自动化检测，配合 Cloudflare Email Worker 实现验证码秒级推送，AES-256-GCM 加密冷库保护敏感数据，asyncio 任务队列 + 死信队列实现批量并发 + 失败自愈。本文从攻防对抗、引擎架构、接码管道三个维度逐层拆解。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="引言"&gt;引言
&lt;/h2&gt;&lt;p&gt;先问一个问题：你从卡网买了一个 Google 账号，改了密码，是不是就安全了？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不是。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;改密码只切断了 6 条&amp;quot;绳子&amp;quot;中的 1 条。卖家仍然可以通过以下方式盗回你的账号：&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;/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;通过&amp;quot;忘记密码&amp;quot;流程，Google 会把重置链接发到卖家的恢复邮箱&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;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Passkey&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;卖家的设备上注册了 Passkey，无需密码即可登录&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;TOTP 2FA 密钥&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;卖家手里有 Base32 密钥，能随时生成你的 2FA 验证码&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;卖家的浏览器可能还保持着登录状态&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;OAuth 授权&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;授权过的第三方应用可以读取邮件、通讯录等数据&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;你只改了密码？卖家用恢复邮箱就能把密码改回来。你改了密码又关了 2FA？Passkey 还在。你把 Passkey 也删了？OAuth 授权的第三方应用还在偷偷读你的数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gmail Sanitizer 要做的事情，就是一口气把这 6 条绳子全部切断。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一核心功能8-步全链路凭据切断"&gt;一、核心功能：8 步全链路凭据切断
&lt;/h2&gt;&lt;p&gt;这个系统的核心是一条 8 步流水线，每一步精确对应一个后门：&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;strong&gt;Step 1&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;登录验证&lt;/td&gt;
 &lt;td&gt;验证旧凭据有效性&lt;/td&gt;
 &lt;td&gt;2FA 挑战、Account Chooser、中间提示页&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 2&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;替换恢复邮箱&lt;/td&gt;
 &lt;td&gt;卖家的恢复邮箱 → 买家自建接码邮箱&lt;/td&gt;
 &lt;td&gt;Google 可能要求邮箱验证码&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 3&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;移除恢复手机&lt;/td&gt;
 &lt;td&gt;卖家绑定的手机号&lt;/td&gt;
 &lt;td&gt;可能需要 Sudo 二次验证&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 4&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;删除所有 Passkey&lt;/td&gt;
 &lt;td&gt;卖家设备的无密码登录凭据&lt;/td&gt;
 &lt;td&gt;循环删除，最多 20 个&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 5&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;重置 2FA&lt;/td&gt;
 &lt;td&gt;旧 TOTP 密钥 → 新 Base32 密钥&lt;/td&gt;
 &lt;td&gt;需要提取页面上的 Base32 密钥文本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 6&lt;/strong&gt;&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;&lt;strong&gt;Step 7&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;撤销 OAuth 授权&lt;/td&gt;
 &lt;td&gt;所有第三方应用权限&lt;/td&gt;
 &lt;td&gt;循环撤销，最多 30 个&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Step 8&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;新凭据验证&lt;/td&gt;
 &lt;td&gt;确认所有切断生效&lt;/td&gt;
 &lt;td&gt;用新密码 + 新 2FA 重新登录&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;注意步骤顺序不是 1-2-3-4-5-6-7-8，而是 &lt;strong&gt;1-2-5-4-3-6-7-8&lt;/strong&gt;——Step 5（重置 2FA）被提前到 Step 4（删除 Passkey）之前执行。为什么？因为 Step 5 需要在 Sudo Gate 中输入旧 TOTP 码来验证身份，如果先删了 Passkey 可能导致 Google 挑选 Passkey 作为 Sudo 验证方式却找不到，引发意外的验证失败。&lt;/p&gt;
&lt;h3 id="11-sudo-gategoogle-的二次验证拦截"&gt;1.1 Sudo Gate：Google 的二次验证拦截
&lt;/h3&gt;&lt;p&gt;这是整个系统最精巧的部分。&lt;/p&gt;
&lt;p&gt;Google 在你修改安全设置时，会弹出&amp;quot;Sudo Gate&amp;quot;——一个二次身份验证页面。问题是，Sudo Gate 不是固定的，Google 会根据你的账号状态动态选择挑战方式：&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;handle_google_sudo_gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totp_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&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;gmail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recovery_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&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;for&lt;/span&gt; &lt;span class="n"&gt;cycle&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# 最多循环 6 次&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&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="c1"&gt;# 1. Account Chooser（会话过期）&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="s2"&gt;&amp;#34;accountchooser&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_url&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 2. 2FA 方式选择页&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="s2"&gt;&amp;#34;challenge/selection&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_url&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;# 智能选择：优先 recovery email &amp;gt; TOTP&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="c1"&gt;# 3. 恢复邮箱验证 (challenge/kpe)&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;is_rec_email_challenge&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;recovery_email&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 4. 密码重输 (challenge/pwd)&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;is_pwd_challenge&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 5. TOTP 二次验证 (challenge/totp)&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;is_totp_challenge&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;totp_secret&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;# 生成并输入 TOTP 验证码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键设计：&lt;strong&gt;while 循环&lt;/strong&gt;。Google 可能在一次操作中连续弹出多种挑战（先要密码，再要 TOTP），所以 Sudo Gate 处理器设计为最多循环 6 次，每次检测当前 URL 和页面元素，动态选择对应的处理策略。不是 &lt;code&gt;if-else&lt;/code&gt;，而是 &lt;code&gt;for cycle in range(6)&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="12-totp-密钥提取从页面-html-中挖掘-base32"&gt;1.2 TOTP 密钥提取：从页面 HTML 中挖掘 Base32
&lt;/h3&gt;&lt;p&gt;Step 5 重置 2FA 时，需要从 Google 的 Authenticator 设置页面提取新的 Base32 密钥。这个密钥显示在页面上的格式是 4 字符一组、空格分隔的文本（如 &lt;code&gt;ABCD EFGH IJKL MNOP&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-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第一层：正则匹配 4-8 组 Base32 字符块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;m_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&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="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;\b(?:[a-zA-Z2-7]&lt;/span&gt;&lt;span class="si"&gt;{4}&lt;/span&gt;&lt;span class="s2"&gt;\s+){3,7}[a-zA-Z2-7]&lt;/span&gt;&lt;span class="si"&gt;{4}&lt;/span&gt;&lt;span class="s2"&gt;\b&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="n"&gt;dialog_text&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;if&lt;/span&gt; &lt;span class="n"&gt;m_groups&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;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m_groups&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&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="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upper&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="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&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;new_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;candidate&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="c1"&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;new_secret&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;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;xpath://div[@role=&amp;#39;dialog&amp;#39;]//...&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="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;\b([a-zA-Z2-7]{16,32})\b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&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="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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AUTHENTICATOR&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;VERIFICATION&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&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="n"&gt;new_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;提取到密钥后，立即用 &lt;code&gt;pyotp.TOTP(new_secret).now()&lt;/code&gt; 生成验证码填入确认框，完成 2FA 重置闭环。&lt;/p&gt;
&lt;h3 id="13-断点续跑任意步骤中断后恢复"&gt;1.3 断点续跑：任意步骤中断后恢复
&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-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;step2_email_changed&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&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;code&gt;StepProgress&lt;/code&gt; 用 10 个布尔字段精确记录每一步的完成状态。重试时，引擎检查哪些步骤已完成，直接跳过：&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;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_progress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step2_email_changed&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;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_step2_recovery_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;account&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;这意味着如果 Step 5 因为网络超时失败，重试时会跳过 Step 1-4 直接从 Step 5 开始。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二技术架构"&gt;二、技术架构
&lt;/h2&gt;&lt;h3 id="21-双引擎设计"&gt;2.1 双引擎设计
&lt;/h3&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;DrissionPage 引擎&lt;/th&gt;
 &lt;th&gt;Playwright 引擎&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Chrome 类型&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;真实 Chrome 进程&lt;/td&gt;
 &lt;td&gt;Chromium 内核&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;反检测能力&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;天然通过——就是真 Chrome&lt;/td&gt;
 &lt;td&gt;需要 JS 注入伪装&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;并发模式&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;每个任务独立端口 + Profile&lt;/td&gt;
 &lt;td&gt;每个任务独立 BrowserContext&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;开发调试（API 更友好）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;进程隔离&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;每个账号独立 Chrome 进程&lt;/td&gt;
 &lt;td&gt;同一 Browser 下的 Context 隔离&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;DrissionPage 引擎是生产首选。它直接控制真实 Chrome 浏览器，Google 的反自动化检测基本无效——因为从 Google 的角度看，这就是一个普通用户在操作浏览器。&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-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;_make_options&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ChromiumOptions&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_find_free_port&lt;/span&gt;&lt;span class="p"&gt;()&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; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_local_port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&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;# 独立 Profile 目录，防止 Chrome SingletonLock 死锁&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;profile_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;data/chrome_profiles/profile_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_user_data_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profile_dir&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;每个账号对应一个独立的 Chrome 实例（独立端口 + 独立 Profile），彻底避免了并发时的 Cookie 串扰和 SingletonLock 死锁。&lt;/p&gt;
&lt;h3 id="22-反检测体系"&gt;2.2 反检测体系
&lt;/h3&gt;&lt;p&gt;Playwright 引擎需要额外的反检测处理。&lt;code&gt;stealth_browser.py&lt;/code&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;// 隐藏 webdriver 属性
&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;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;webdriver&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="c1"&gt;// 伪造 plugins（无头浏览器默认为空）
&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;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;plugins&amp;#39;&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;get&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;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;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Chrome PDF Plugin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;internal-pdf-viewer&amp;#39;&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="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;配合随机 User-Agent、随机分辨率、随机时区和随机语言：&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="n"&gt;_USER_AGENTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Chrome/125.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Chrome/124.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 5 种&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;_VIEWPORTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="n"&gt;x1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1440&lt;/span&gt;&lt;span class="n"&gt;x900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 5 种&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;_LOCALES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;en-US&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;zh-CN&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 5 种&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;_TIMEZONES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;America/New_York&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Asia/Shanghai&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 5 种&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个 BrowserContext 从这些池子中随机组合，确保指纹不重复。&lt;/p&gt;
&lt;h3 id="23-任务队列--死信队列"&gt;2.3 任务队列 + 死信队列
&lt;/h3&gt;&lt;p&gt;并发调度用经典的 asyncio 生产者-消费者模型：&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;│ 任务入队 │────▶│ asyncio.Queue │
&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; │ Worker 0 │ │ Worker 1 │ │ Worker N │
&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; │ DrissionEngine.run_sync(task) │
&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; │ VERIFIED │ │ FAILED │──▶ 死信队列
&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;ul&gt;
&lt;li&gt;&lt;strong&gt;不可重试类型自动隔离&lt;/strong&gt;：&lt;code&gt;WRONG_PASSWORD&lt;/code&gt;（密码错误）、&lt;code&gt;ACCOUNT_DISABLED&lt;/code&gt;（封号）、&lt;code&gt;CAPTCHA_BLOCKED&lt;/code&gt;（风控拦截）—— 这些重试也没用，直接进人工审核&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可重试类型指数退避&lt;/strong&gt;：&lt;code&gt;STEP_TIMEOUT&lt;/code&gt;（超时）、&lt;code&gt;PROXY_ERROR&lt;/code&gt;（代理挂了）—— 等 2^n 秒后重试，最多 3 次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Passkey 误判恢复&lt;/strong&gt;：如果失败详情包含 &lt;code&gt;passkeyenrollment&lt;/code&gt; 或 &lt;code&gt;speedbump&lt;/code&gt;，说明不是真正的失败而是卡在了中间提示页，强制纳入可重试队列&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="24-aes-256-gcm-加密冷库"&gt;2.4 AES-256-GCM 加密冷库
&lt;/h3&gt;&lt;p&gt;所有敏感字段（新密码、TOTP 密钥、Cookie）在存入数据库前经过 AES-256-GCM 加密：&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;class&lt;/span&gt; &lt;span class="nc"&gt;_Cipher&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;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plaintext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&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;nonce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 96-bit 随机 nonce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_aesgcm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plaintext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&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&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 class="n"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# nonce 和密文拼接后存储&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GCM 模式提供认证加密——不仅保密，还防篡改。即使数据库被拖库，没有 32 字节主密钥也无法解密。而且每次加密使用随机 nonce，相同明文产生不同密文，抵抗已知明文攻击。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三验证码邮件管道"&gt;三、验证码邮件管道
&lt;/h2&gt;&lt;p&gt;Step 2（替换恢复邮箱）可能触发 Google 的邮箱验证码。系统通过 Cloudflare Email Worker 实现秒级接码：&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;Google 发送验证码邮件
&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;Cloudflare Email Routing（Catch-All 规则）
&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;Email Worker（正则提取 6 位验证码）
&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;HTTP POST → 主程序回调接口
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Email Worker 的正则提取覆盖了 Google 验证码邮件的多种模板：&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codePatterns&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="sr"&gt;/\b([0-9]{6})\b(?=\s*(?:is your|是您的|verification|验证|code))/i&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="sr"&gt;/(?:verification code|验证码)[^\d]*([0-9]{6})/i&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="sr"&gt;/G-([0-9]{6})/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Google 特定格式 &amp;#34;G-123456&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sr"&gt;/\b([0-9]{6})\b/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 兜底：提取第一个 6 位数字
&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;如果邮件通道超时（30 秒），系统还有一个优雅降级——直接在终端提示操作者手动输入验证码：&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;if&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isatty&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;user_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;6-digit code (or Enter to skip): &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&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;hr&gt;
&lt;h2 id="四安全设计亮点"&gt;四、安全设计亮点
&lt;/h2&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;每账号独立 Chrome 进程 + 独立端口 + 独立 Profile&lt;/td&gt;
 &lt;td&gt;防 Cookie 串扰、防 SingletonLock&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;加密存储&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;AES-256-GCM + 随机 Nonce&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;&lt;code&gt;random.uniform(0.8, 2.0)&lt;/code&gt; 秒操作间隔 + Worker 领任务前 1.5-5.0 秒抖动&lt;/td&gt;
 &lt;td&gt;降低 Google 风控触发率&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;中间提示页自动跳过&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;智能识别 Passkey 引导、恢复邮箱确认等弹窗&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;18 位、大小写 + 数字 + 符号、&lt;code&gt;secrets&lt;/code&gt; 模块生成&lt;/td&gt;
 &lt;td&gt;通过 Google 密码强度校验&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;密码热切换&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Step 6 修改密码后立即 &lt;code&gt;cred.password = new_password&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;后续步骤用新密码通过 Sudo Gate&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="五与同类方案对比"&gt;五、与同类方案对比
&lt;/h2&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;Gmail Sanitizer&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;取决于经验（通常漏 2-3 个）&lt;/td&gt;
 &lt;td&gt;1-2 个（通常只改密码）&lt;/td&gt;
 &lt;td&gt;全部 6 类后门&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;单号耗时&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;15-30 分钟&lt;/td&gt;
 &lt;td&gt;3-5 分钟&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;1&lt;/td&gt;
 &lt;td&gt;1-3&lt;/td&gt;
 &lt;td&gt;20+（可配置）&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;td&gt;支持（10 步粒度）&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;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;明文&lt;/td&gt;
 &lt;td&gt;明文&lt;/td&gt;
 &lt;td&gt;AES-256-GCM&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;Selenium（易被检测）&lt;/td&gt;
 &lt;td&gt;真实 Chrome / 指纹随机化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Sudo Gate 处理&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;人工判断&lt;/td&gt;
 &lt;td&gt;通常卡住&lt;/td&gt;
 &lt;td&gt;6 种挑战类型自动适配&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="写在最后"&gt;写在最后
&lt;/h2&gt;&lt;p&gt;Gmail Sanitizer 这个项目的技术含量不在于&amp;quot;自动化&amp;quot;本身——Selenium 填表单谁都会。它的价值在于&lt;strong&gt;对 Google 安全机制的深度理解&lt;/strong&gt;：知道 Google 有哪些后门、知道 Sudo Gate 有哪些挑战类型、知道 Base32 密钥在页面上以什么格式显示、知道修改密码后旧 TOTP 密钥还能用多久。&lt;/p&gt;
&lt;p&gt;从工程角度看，断点续跑 + 死信队列 + 加密冷库 的组合，让它从&amp;quot;一次性脚本&amp;quot;变成了&amp;quot;可运维的生产系统&amp;quot;。这是大多数同类工具缺失的维度。&lt;/p&gt;
&lt;p&gt;对于大体量的 Google 账号采购场景，先批量跑一遍 8 步清洗，再投入使用——这是成本最低的安全保障。&lt;/p&gt;</description></item><item><title>aBaiAutoplus 深度拆解：当「注册机」进化成 AI 账号工厂</title><link>https://blog.7qiang.com/posts/abai-autoplus-analysis/</link><pubDate>Mon, 01 Jun 2026 17:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/abai-autoplus-analysis/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post aBaiAutoplus 深度拆解：当「注册机」进化成 AI 账号工厂" /&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;：aBaiAutoplus 不止是&amp;quot;注册机&amp;quot;，而是一套完整的 AI 账号自动化工厂——插件化架构支持 12 个平台，协议 + 浏览器双模式，甚至打通了 PayPal / GoPay 付款开通 ChatGPT Plus 的全链路。本文从 HTTP 指纹对抗、邮箱轮换、注册流程引擎到支付协议逆向，逐层拆解其技术内幕，并与同类工具横向对比。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="引言"&gt;引言
&lt;/h2&gt;&lt;p&gt;先问一个问题：一个账号注册工具，和&amp;quot;AI 账号工厂&amp;quot;之间差了多远？&lt;/p&gt;
&lt;p&gt;答案是：差了&lt;strong&gt;付费通道&lt;/strong&gt;和&lt;strong&gt;生命周期管理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;市面上注册 ChatGPT 账号的工具不少。用 Selenium 填个表单、接个验证码、输出 token —— 这是 2023 年的及格线。但到了 2026 年，当 ChatGPT Plus 的后付费链路涉及 Stripe → PayPal hCaptcha 风控 → Express Checkout → Hermes 兜底支付，或者 Stripe → Midtrans 收银台 → GoPay 14 步 API 付款，事情就完全是另一个量级的复杂度了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;aBaiAutoplus&lt;/strong&gt; —— GitHub 上架两天 311 Star、208 Fork，基于 &lt;code&gt;any-auto-register&lt;/code&gt; 二次开发，在插件化注册框架之上硬是接上了 GoPay 和 PayPal 两条付费管道，把注册工具做成了&amp;quot;账号 + Plus 订阅&amp;quot;的全自动生产线。&lt;/p&gt;
&lt;p&gt;本文不是功能罗列。我们从架构、协议对抗、支付链路、生态对比四个维度切入，拆解它到底做了什么、怎么做到的、以及相比同类工具是「换皮」还是「进化」。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一架构全景插件化的账号工厂"&gt;一、架构全景：插件化的&amp;quot;账号工厂&amp;quot;
&lt;/h2&gt;&lt;p&gt;先说结论：这是一个标准的 &lt;strong&gt;DDD（领域驱动设计）分层架构&lt;/strong&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;api/ ── FastAPI 路由层（REST + SSE 实时日志推送）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;application/ ── 应用编排层（任务调度、付款流水线、多租户 API）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;domain/ ── 领域模型（Account / Task / Proxy / Platform 抽象）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;core/ ── 核心能力层（平台基类、注册引擎、代理池、生命周期）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;platforms/ ── 平台插件层（每个平台一个独立包）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;providers/ ── Provider 插件层（邮箱 / 验证码 / 接码 / 代理驱动）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;frontend/ ── React + TypeScript + Vite + TailwindCSS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;electron/ ── Electron 桌面端打包
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="11-插件的自发现机制"&gt;1.1 插件的自发现机制
&lt;/h3&gt;&lt;p&gt;系统的灵魂在 &lt;code&gt;core/registry.py&lt;/code&gt;。启动时用 &lt;code&gt;pkgutil.iter_modules&lt;/code&gt; 扫描 &lt;code&gt;platforms/&lt;/code&gt; 下的所有 Python 包，任何带 &lt;code&gt;@register&lt;/code&gt; 装饰器的 &lt;code&gt;BasePlatform&lt;/code&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="c1"&gt;# 一个平台插件的典型结构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@register&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChatGPTPlatform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BasePlatform&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;chatgpt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;display_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ChatGPT&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;supported_executors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;headless&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;headed&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="n"&gt;supported_identity_modes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mailbox&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="n"&gt;supported_oauth_providers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;google&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;microsoft&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="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;plus_payment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;paypal_checkout&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;这意味着添加新平台不需要修改任何核心代码——你在 &lt;code&gt;platforms/&lt;/code&gt; 下新建一个包，实现 &lt;code&gt;plugin.py&lt;/code&gt;，定义 &lt;code&gt;build_protocol_mailbox_adapter()&lt;/code&gt; 和 &lt;code&gt;build_browser_registration_adapter()&lt;/code&gt;，系统启动时它就会出现在 Web UI 里。&lt;/p&gt;
&lt;h3 id="12-注册流程引擎三种模式统一抽象"&gt;1.2 注册流程引擎：三种模式统一抽象
&lt;/h3&gt;&lt;p&gt;这是整个架构最精巧的部分。所有平台的注册逻辑被收敛到三个标准 Flow 类中：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Flow&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;ProtocolMailboxFlow&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;纯 HTTP API 注册 + 邮箱验证码&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;worker_builder&lt;/code&gt; → &lt;code&gt;register_runner&lt;/code&gt; → &lt;code&gt;result_mapper&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;BrowserRegistrationFlow&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;需要浏览器的注册（Turnstile / hCaptcha / OAuth）&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;browser_worker_builder&lt;/code&gt; → &lt;code&gt;browser_register_runner&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;ProtocolOAuthFlow&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;OAuth 协议订阅（Google / Microsoft 登录）&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;oauth_runner&lt;/code&gt; → &lt;code&gt;result_mapper&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三者的共同点是都依赖 &lt;strong&gt;Adapter 模式&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="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&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;class&lt;/span&gt; &lt;span class="nc"&gt;ProtocolMailboxAdapter&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;result_mapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&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; &lt;span class="n"&gt;worker_builder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt; &lt;span class="c1"&gt;# Worker 构造器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;register_runner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&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; &lt;span class="n"&gt;otp_spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OtpSpec&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&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; &lt;span class="n"&gt;link_spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LinkSpec&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&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; &lt;span class="n"&gt;use_captcha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&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;每个平台的 &lt;code&gt;plugin.py&lt;/code&gt; 只需「组装」一个 Adapter 并返回，Flow 引擎负责执行环境的构建（代理注入、邮箱轮换、验证码回调、超时控制、取消检查）。这种设计让&amp;quot;注册&amp;quot;这件事变成了&lt;strong&gt;声明式配置&lt;/strong&gt;——开发者不需要理解并发控制、异常重试、SSE 日志推送等技术细节。&lt;/p&gt;
&lt;h3 id="13-技术栈选型中的安全考量"&gt;1.3 技术栈选型中的安全考量
&lt;/h3&gt;&lt;p&gt;注意几个关键组件的选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTTP 客户端&lt;/strong&gt;：&lt;code&gt;curl_cffi&lt;/code&gt; 而非 &lt;code&gt;requests&lt;/code&gt; 或 &lt;code&gt;httpx&lt;/code&gt;。原因很简单——&lt;code&gt;curl_cffi&lt;/code&gt; 能伪造 TLS 指纹（&lt;code&gt;impersonate=&amp;quot;chrome136&amp;quot;&lt;/code&gt;），让请求在 TLS 握手层面就&amp;quot;看起来像浏览器&amp;quot;。Cloudflare / Akamai 等 WAF 对 &lt;code&gt;requests&lt;/code&gt; 库的 JA3 指纹一抓一个准。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器引擎&lt;/strong&gt;：Playwright（Chromium）+ Camoufox（反指纹）+ BitBrowser（指纹浏览器）。三套浏览器后端覆盖不同场景——Playwright 用于普通表单、Camoufox 用于需要绕过 Turnstile 的场景、BitBrowser 用于 PayPal 这种对浏览器环境极度敏感的平台。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;桌面端&lt;/strong&gt;：Electron 内嵌完整 Python 后端，不依赖用户安装 Python 环境。这种&amp;quot;all-in-one&amp;quot;打包方式是降低使用门槛的关键——用户双击 &lt;code&gt;.dmg&lt;/code&gt; 或 &lt;code&gt;.exe&lt;/code&gt; 就能用。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二核心突破口从注册到付款的最后一公里"&gt;二、核心突破口：从&amp;quot;注册&amp;quot;到&amp;quot;付款&amp;quot;的最后一公里
&lt;/h2&gt;&lt;p&gt;如果说插件化架构是骨架，那付款集成就是灵魂。这是 aBaiAutoplus 与上游 &lt;code&gt;any-auto-register&lt;/code&gt; 最本质的分野。&lt;/p&gt;
&lt;h3 id="21-gopay-付款链路14-步-api-协议"&gt;2.1 GoPay 付款链路：14 步 API 协议
&lt;/h3&gt;&lt;p&gt;印尼 GoPay 是 ChatGPT Plus 订阅的一条「野路子」。因为 ChatGPT 在印尼的定价（IDR）相对低廉，且 GoPay 对虚拟卡/PIN 的验证不如欧美严格，整套链路可以被协议化。&lt;/p&gt;
&lt;p&gt;其流水线分三步（实现见 &lt;code&gt;application/gopay_pay_chatgpt.py&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;步骤一【协议】：调用 generate_plus_link(country=ID, currency=IDR)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 拿到 Stripe Hosted Checkout 的 cashier_url
&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;步骤二【浏览器】：打开 cashier_url → 等待页面自动跳转到 Midtrans 域
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 捕获 midtrans_url（Snap v3/v4 重定向 URL）
&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;步骤三【协议】：GoPayPayment.pay(midtrans_url, account)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 14 步 Midtrans API：生成支付token → 启动交易 → GoPay 扫码/确认 → 回调
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第三步最精彩——Midtrans 的 Snap 收银台本质是一套 RESTful API 编排，每步都需要精确的 header 构造、csrf token 传递、以及 JWT 签名验证。项目在 &lt;code&gt;platforms/gopay-deploy/&lt;/code&gt; 中做了一套完整的 GoPay 协议 Worker，从账号登录、PIN 验证、余额查询到付款确认，全链路协议化。&lt;/p&gt;
&lt;p&gt;同时注意到一个巧妙的工程手段——&lt;strong&gt;PhoneTTLGuard&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;class&lt;/span&gt; &lt;span class="nc"&gt;PhoneTTLGuard&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;&amp;#34;&amp;#34;Hero-SMS 号码 20 分钟自动回收的护栏&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl_seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1200&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ttl_seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ttl_seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monotonic&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;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ttl_seconds&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;RuntimeError&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为接码平台的印尼号码只有 20 分钟有效期，如果你在注册 GoPay 后超过 20 分钟才去调用付款接口，号码已被回收，短信验证码就收不到了。这个护栏用 &lt;code&gt;time.monotonic()&lt;/code&gt;（不受系统时钟回拨影响）在每一步执行前检查，超时直接判失败——干净利落的工程防御。&lt;/p&gt;
&lt;h3 id="22-paypal-付款链路har-协议逆向的艺术"&gt;2.2 PayPal 付款链路：HAR 协议逆向的艺术
&lt;/h3&gt;&lt;p&gt;比 GoPay 更复杂的是 PayPal。ChatGPT Plus 的后付费链路会经过 Stripe → PayPal 的审批协议跳转，PayPal 端有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;hCaptcha passive 检测&lt;/strong&gt;（包含约 2200 字符的签名 JWT）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic Risk Center 企业风控&lt;/strong&gt;（5 次交叉验证请求）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SignUp Guest 注册流&lt;/strong&gt;（包括手机号验证、地址填充、卡片绑定）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hermes 兜底支付&lt;/strong&gt;（OPT_OUT 模式，$0 trial 不产生真实扣款）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;项目仓库中一份 77MB 的 HAR 文件 &lt;code&gt;checkout-20260523-160436-04xg0pylps_edu.hsxhome.com.har&lt;/code&gt;（含 846 个请求），被逐帧反推成了协议文档 &lt;code&gt;PAYPAL_PROTOCOL_FLOW.md&lt;/code&gt;，拆解出 6 个 Stage、20+ 个端点的完整调用链。&lt;/p&gt;
&lt;p&gt;最值得关注的技术点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① hCaptcha passive 的&amp;quot;不战而胜&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PayPal 的 &lt;code&gt;/auth/validatecaptcha&lt;/code&gt; 端点接受 &lt;code&gt;hcaptchaToken=NOT_REACHABLE&lt;/code&gt; 作为参数——也就是说，在某些条件下，PayPal 自己的前端 JavaScript 在检测不到 hCaptcha 时也不会拒绝请求，而是走到一个 authchallengenodeweb 模板（返回 200 + 7387 字节 HTML）。真正的 hCaptcha 校验在另一个端点 &lt;code&gt;/auth/verifyhcaptchapassive&lt;/code&gt; 中触发，需要 hCaptcha SDK 生成的 &lt;code&gt;P1_&amp;lt;签名JWT&amp;gt;&lt;/code&gt; token。&lt;/p&gt;
&lt;p&gt;这个发现意味着：&lt;strong&gt;如果能绕过 PayPal 的 Generic Risk Center 风控评分，hCaptcha 可能根本不会被触发&lt;/strong&gt;。这是典型的&amp;quot;从协议层面理解风控触发条件&amp;quot;的逆向思路，而不是硬着头皮去对着 hCaptcha 死磕。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Hermes 兜底支付的 $0 trial 秘密&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在前几次 addCard 时，GraphQL mutate 返回 &lt;code&gt;ISSUER_DECLINE / CARD_GENERIC_ERROR&lt;/code&gt; 并不代表失败。PayPal 会自动在 redirect URL 追加 &lt;code&gt;addFIContingency=noretry&amp;amp;fallback=1&amp;amp;reason=CARD_GENERIC_ERROR&lt;/code&gt;（base64 编码），把流量导进 &lt;code&gt;/webapps/hermes&lt;/code&gt; 兜底支付。Hermes 里只需发一个 &lt;code&gt;authorize&lt;/code&gt; mutation，带 &lt;code&gt;fundingPreference={&amp;quot;balancePreference&amp;quot;:&amp;quot;OPT_OUT&amp;quot;}&lt;/code&gt;，PayPal 就会直接返回 &lt;code&gt;status=success&lt;/code&gt;——因为它识别到这是一笔 $0 试用的审批授权，不需要真实扣款。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OPT_OUT 是整条链路中最关键的一个参数&lt;/strong&gt;。它告诉 PayPal：“别从任何资金渠道扣款，这是一笔授权审批。” 不掌握这个细节，你会以为 visa 虚拟卡被拒就是失败。掌握了，你就知道这条 HAR 里的所有&amp;quot;失败&amp;quot;步骤都是预期的路由分支。&lt;/p&gt;
&lt;h3 id="23-代理池成功率驱动的智能轮换"&gt;2.3 代理池：成功率驱动的智能轮换
&lt;/h3&gt;&lt;p&gt;代理在 AI 账号注册中是核心竞争力。Cloudflare 对数据中心 IP 的态度越来越严苛，Turnstile 验证码的通过率与 IP 质量直接挂钩。&lt;/p&gt;
&lt;p&gt;aBaiAutoplus 的代理池设计有三种层级：&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;/td&gt;
 &lt;td&gt;按成功率加权轮询，连续失败 5 次自动禁用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;动态 API 提取&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;代理商的 HTTP API 动态提取&lt;/td&gt;
 &lt;td&gt;每次提取新 IP，适合大批量任务&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;旋转网关代理&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;BrightData / Oxylabs / IPRoyal 等&lt;/td&gt;
 &lt;td&gt;固定入口地址，每次请求自动分配不同出口 IP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&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;code&gt;GET /api/stats/by-proxy&lt;/code&gt; 可按代理查询成功率排行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台敏感度区分&lt;/strong&gt;：不同平台对 IP 的容忍度不同，可分别配置代理策略&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="三生态完整性从注册到交付的全链路"&gt;三、生态完整性：从注册到交付的全链路
&lt;/h2&gt;&lt;p&gt;一个只注册不管后续的工具是半成品。aBaiAutoplus 做了完整的生命周期闭环：&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-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# core/lifecycle.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;每&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="n"&gt;小时&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;&lt;span class="n"&gt;有效性检测&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="n"&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;每&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="n"&gt;小时&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt; &lt;span class="n"&gt;自动续期&lt;/span&gt;&lt;span class="err"&gt;（&lt;/span&gt;&lt;span class="n"&gt;当前支持&lt;/span&gt; &lt;span class="n"&gt;ChatGPT&lt;/span&gt; &lt;span class="n"&gt;session_token&lt;/span&gt; &lt;span class="n"&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Trial&lt;/span&gt; &lt;span class="n"&gt;过期扫描&lt;/span&gt;&lt;span class="err"&gt;：&lt;/span&gt;&lt;span class="n"&gt;快过期&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;预警标记&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;已过期&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;状态更新为&lt;/span&gt; &lt;span class="n"&gt;EXPIRED&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这不是装饰性功能——如果你有 200 个 ChatGPT 账号，手动检查每个 token 是否过期是不现实的。生命周期管理器让账号池成为一种「可运营的资源」，而非一次性消耗品。&lt;/p&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-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/api/stats/overview → 全局概览（总数、成功率、状态分布）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/api/stats/by-platform → 按平台统计成功率（看哪个平台风控严）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/api/stats/by-day → 按天注册趋势（看成功率是否在下降）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/api/stats/by-proxy → 代理成功率排行（淘汰低质代理）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/api/stats/errors → 失败错误聚合（分析常见失败原因）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;把成功率数据分析做成独立 API，意味着可以接入 Grafana / Prometheus 等外部监控，而不只是看 Web UI 上的图表。这是「工具」到「运维平台」之间的一条分界线。&lt;/p&gt;
&lt;h3 id="33-账号导出生态"&gt;3.3 账号导出生态
&lt;/h3&gt;&lt;p&gt;注册完的账号需要被消费。支持 6 种导出格式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JSON / CSV&lt;/strong&gt;：常规导出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPA&lt;/strong&gt;：内容发布平台导入格式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sub2API&lt;/strong&gt;：订阅 API 转换器格式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kiro-Go&lt;/strong&gt;：Kiro 平台的 config.json 格式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Any2API&lt;/strong&gt;：开源 API 网关格式（注册完自动推送到网关，即注册即用）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后这个 Any2API 联动很有意思——注册工具本身不提供 API 服务，但它能自动把账号推送到另一个 API 网关项目，让下游消费者通过统一接口获取账号。这是一种「微服务化」的思路：注册工具专注生产，API 网关专注分发。&lt;/p&gt;
&lt;h3 id="34-any2api-自动推送映射"&gt;3.4 Any2API 自动推送映射
&lt;/h3&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;Kiro&lt;/td&gt;
 &lt;td&gt;kiroAccounts&lt;/td&gt;
 &lt;td&gt;账号池&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Grok&lt;/td&gt;
 &lt;td&gt;grokTokens&lt;/td&gt;
 &lt;td&gt;Token 池&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cursor&lt;/td&gt;
 &lt;td&gt;cursorConfig&lt;/td&gt;
 &lt;td&gt;Cookie + 配置&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ChatGPT&lt;/td&gt;
 &lt;td&gt;chatgptConfig&lt;/td&gt;
 &lt;td&gt;Token + 配置&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Blink&lt;/td&gt;
 &lt;td&gt;blinkConfig&lt;/td&gt;
 &lt;td&gt;凭证&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Windsurf&lt;/td&gt;
 &lt;td&gt;windsurfAccounts&lt;/td&gt;
 &lt;td&gt;账号池&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="四横向对比与同类工具的异同"&gt;四、横向对比：与同类工具的异同
&lt;/h2&gt;&lt;h3 id="41-any-auto-register上游项目"&gt;4.1 any-auto-register（上游项目）
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;维度&lt;/th&gt;
 &lt;th&gt;any-auto-register&lt;/th&gt;
 &lt;th&gt;aBaiAutoplus&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;⭐ Star&lt;/td&gt;
 &lt;td&gt;2529&lt;/td&gt;
 &lt;td&gt;311&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;🍴 Fork&lt;/td&gt;
 &lt;td&gt;885&lt;/td&gt;
 &lt;td&gt;208&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;平台数&lt;/td&gt;
 &lt;td&gt;13+&lt;/td&gt;
 &lt;td&gt;12（继承上游 + 新增 GoPay）&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;tr&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;PayPal 付款&lt;/td&gt;
 &lt;td&gt;❌&lt;/td&gt;
 &lt;td&gt;✅（浏览器 PayPal 结账）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GoPay 付款&lt;/td&gt;
 &lt;td&gt;❌&lt;/td&gt;
 &lt;td&gt;✅（协议 14 步 API 付款）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Any2API 联动&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;/td&gt;
 &lt;td&gt;SMS-Activate / HeroSMS&lt;/td&gt;
 &lt;td&gt;+ SMSPool / SMSBower&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;C 端管理门户&lt;/td&gt;
 &lt;td&gt;❌&lt;/td&gt;
 &lt;td&gt;✅（customer_portal_api）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;桌面客户端&lt;/td&gt;
 &lt;td&gt;Mac / Win（社区版）&lt;/td&gt;
 &lt;td&gt;Mac / Win（完整版）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;本质差异&lt;/strong&gt;：&lt;code&gt;any-auto-register&lt;/code&gt; 做了「注册」，aBaiAutoplus 做了「注册 + 付费」。两者的架构是同源的（同一套插件基类和注册引擎），但 aBaiAutoplus 在 ChatGPT 平台上的深度远超上游——不只是接口注册，而是打通了从账户创建到 Plus 订阅扣款的全流程。&lt;/p&gt;
&lt;p&gt;可以这么说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;any-auto-register&lt;/code&gt; = 注册框架 + 多平台适配器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aBaiAutoplus&lt;/code&gt; = 注册框架 + ChatGPT Plus 付费工程 + GoPay 全套协议&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="42-gpt-auto-register397"&gt;4.2 gpt-auto-register（⭐397）
&lt;/h3&gt;&lt;p&gt;最直接的单平台竞品。基于 Python + Selenium，专注 ChatGPT 账号注册。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;维度&lt;/th&gt;
 &lt;th&gt;gpt-auto-register&lt;/th&gt;
 &lt;th&gt;aBaiAutoplus&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;浏览器引擎&lt;/td&gt;
 &lt;td&gt;Selenium（单引擎）&lt;/td&gt;
 &lt;td&gt;Playwright / Camoufox / BitBrowser（三引擎）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;架构&lt;/td&gt;
 &lt;td&gt;单体脚本&lt;/td&gt;
 &lt;td&gt;插件化 DDD 分层&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;平台支持&lt;/td&gt;
 &lt;td&gt;ChatGPT 单一平台&lt;/td&gt;
 &lt;td&gt;12 平台&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;付款集成&lt;/td&gt;
 &lt;td&gt;❌&lt;/td&gt;
 &lt;td&gt;✅（PayPal + GoPay）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Web UI&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;React + SSE 实时日志&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;tr&gt;
 &lt;td&gt;TLS 指纹&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;curl_cffi impersonate&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;桌面客户端&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;Electron&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;差距不在功能数量，在架构理念&lt;/strong&gt;。&lt;code&gt;gpt-auto-register&lt;/code&gt; 是一个能用的注册脚本；&lt;code&gt;aBaiAutoplus&lt;/code&gt; 是一个可扩展的注册平台。&lt;/p&gt;
&lt;h3 id="43-chatgpt-auto-register13"&gt;4.3 chatgpt-auto-register（⭐13）
&lt;/h3&gt;&lt;p&gt;基于 &lt;code&gt;undetected-chromedriver&lt;/code&gt; 的入门级实现。功能最基础，适合学习原理，不具备生产级可用性。与 aBaiAutoplus 不在同一量级，不做详细对比。&lt;/p&gt;
&lt;h3 id="44-差异化总结"&gt;4.4 差异化总结
&lt;/h3&gt;&lt;p&gt;如果把「AI 账号注册工具」的进化分为三个阶段：&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;第一代（2023） Selenium + 手动配置 → 注册成功
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第二代（2024-25） Playwright + 多平台 + 插件化 → 注册 + 管理
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第三代（2026） 协议逆向 + 付费打通 + 微服务生态 → 全链路自动化
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;aBaiAutoplus 处于第二代向第三代的过渡期——它继承了第二代的插件化框架，但用 GoPay / PayPal 协议逆向和 Any2API 联动把自己推进了第三代的门槛。三者的核心差异体现在付费集成、TLS 对抗深度、以及生态完整度上。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五工程细节中值得关注的亮点"&gt;五、工程细节中值得关注的亮点
&lt;/h2&gt;&lt;h3 id="51-tls-指纹伪装的双层策略"&gt;5.1 TLS 指纹伪装的双层策略
&lt;/h3&gt;&lt;p&gt;项目在 HTTP 层面有两套请求方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;curl_cffi&lt;/strong&gt;（&lt;code&gt;core/http_client.py&lt;/code&gt;）：默认 &lt;code&gt;impersonate=&amp;quot;chrome136&amp;quot;&lt;/code&gt;，伪造完整的 TLS 握手指纹&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tls_client&lt;/strong&gt;（&lt;code&gt;core/tls.py&lt;/code&gt;）：更轻量的选择，用于 GoPay 等对 TLS 检测不那么严格的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种「双层策略」是有深度的——curl_cffi 的 impersonate 虽然真实度高，但附带性能开销；对于不需要高伪装的 API 请求，退回到 tls_client 能提升吞吐量。&lt;/p&gt;
&lt;h3 id="52-邮箱层的深度防御"&gt;5.2 邮箱层的「深度防御」
&lt;/h3&gt;&lt;p&gt;9 种邮箱 Provider 不是简单的多选，而是一种&lt;strong&gt;分层防护策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自己的域名邮箱&lt;/strong&gt;（Laoudo）：稳定性最高，适合重要账号，不会被封&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自建 Cloudflare Worker 邮箱&lt;/strong&gt;：完全可控，邮箱域名随机，难以被平台封禁&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;公共临时邮箱&lt;/strong&gt;（DuckMail / TempMail.lol）：零配置，适合快速测试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MoeMail 自动注册&lt;/strong&gt;：连邮箱也是自动创建的，适合大规模并发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同场景用不同邮箱，这是一种&lt;strong&gt;对抗意识&lt;/strong&gt;——当平台开始针对特定邮箱域名做风控时，你有备选方案。&lt;/p&gt;
&lt;h3 id="53-验证码求解的递进策略"&gt;5.3 验证码求解的递进策略
&lt;/h3&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;本地 Solver（Camoufox 自动点击 checkbox）&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;Turnstile checkbox，最快最省&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;远程 Solver（YesCaptcha / 2Captcha）&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;需要图片识别或本地失败时&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;手动介入&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;极端风控场景&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;「先本地、再远程、最后手动」的递进逻辑，比直接调打码平台更经济。&lt;/p&gt;
&lt;h3 id="54-开源安全审计的工程良心"&gt;5.4 开源安全审计的&amp;quot;工程良心&amp;quot;
&lt;/h3&gt;&lt;p&gt;项目开源前做了一份详细的安全审计（&lt;code&gt;OPEN_SOURCE_RELEASE.md&lt;/code&gt;），发现的 P0 级问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;81 个真实 ChatGPT 账号明文凭证已被 git 跟踪&lt;/li&gt;
&lt;li&gt;8 个 GoPay 账号的手机号 + PIN 明文泄露&lt;/li&gt;
&lt;li&gt;13 个调试 dump 文件含 PayPal / Stripe 实时 cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这份审计本身就是一个有价值的技术文档——它展示了「开源前要做哪些安全检查」的完整 checklist：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;扫描 git 历史中的凭证文件&lt;/li&gt;
&lt;li&gt;检查源码中的硬编码 API Key&lt;/li&gt;
&lt;li&gt;审查第三方 APK 逆向常量是否可公开&lt;/li&gt;
&lt;li&gt;验证 &lt;code&gt;.gitignore&lt;/code&gt; 规则是否生效&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git filter-repo&lt;/code&gt; 重写历史的完整命令&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每个打算开源的开发者都应该读一遍这份文档。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六局限与风险"&gt;六、局限与风险
&lt;/h2&gt;&lt;h3 id="61-技术局限"&gt;6.1 技术局限
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GoPay 地域锁定&lt;/strong&gt;：依赖印尼手机号 + 印尼 IP，对中国用户不友好&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PayPal 浏览器自动化不稳定&lt;/strong&gt;：BitBrowser profile 持久化是双刃剑——历史 cookie 积累后可能触发异常检测&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Camoufox 依赖&lt;/strong&gt;：本地 Solver 依赖于 Camoufox 的反指纹浏览器，ARM 架构支持有限&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MoeMail 公共实例不可控&lt;/strong&gt;：依赖第三方部署的实例稳定性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="62-运维负担"&gt;6.2 运维负担
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;3.7M 行 Python（含依赖）不是小工程，依赖更新和兼容性维护是个长期问题&lt;/li&gt;
&lt;li&gt;跨平台浏览器自动化（Playwright + Camoufox + BitBrowser）的环境配置复杂度高&lt;/li&gt;
&lt;li&gt;多接码渠道、多验证码渠道的 API 轮换和余额管理需要持续关注&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="63-法律与道德边界"&gt;6.3 法律与道德边界
&lt;/h3&gt;&lt;p&gt;项目在 README 中明确了「仅供学习研究」的定位，并且基于 AGPL-3.0 许可证。但必须指出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自动化注册违反几乎所有目标平台的 ToS&lt;/li&gt;
&lt;li&gt;协议化支付链路可能涉及支付欺诈的法律风险&lt;/li&gt;
&lt;li&gt;印尼 GoPay 的 APK 逆向常量（&lt;code&gt;CLIENT_SECRET&lt;/code&gt; 等）存在 ToS 和版权问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;技术是好技术，但使用场景需要谨慎判断。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七总结"&gt;七、总结
&lt;/h2&gt;&lt;p&gt;aBaiAutoplus 之所以值得深入分析，不是因为它「又多了一个注册工具」，而是因为它展示了注册工具从&lt;strong&gt;脚本&lt;/strong&gt;到&lt;strong&gt;平台&lt;/strong&gt;的完整进化路径。&lt;/p&gt;
&lt;p&gt;它的核心价值不在于星星数（311 相比上游的 2529 还差得远），而在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;架构上&lt;/strong&gt;：插件化 + DDD 分层，让注册能力可扩展、可维护&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术上&lt;/strong&gt;：支付协议逆向（PayPal 6 Stage + GoPay 14 步），把&amp;quot;注册&amp;quot;延伸到&amp;quot;付费&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程上&lt;/strong&gt;：代理池智能轮换、邮箱分层防护、TLS 指纹对抗，形成了一个完整的反风控体系&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生态上&lt;/strong&gt;：Any2API 联动、多格式导出、customer_portal_api，让注册工具成为可运营的基础设施&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;与同类工具相比，它最大的差异化优势是&lt;strong&gt;付费链路的打通&lt;/strong&gt;——这是三个对比项目都不具备的能力。GoPay 协议付款和 PayPal 浏览器结账这两条「野路子」，背后是扎实的 HAR 分析和协议逆向工作，不是简单的 API 拼接。&lt;/p&gt;
&lt;p&gt;当然，它的&amp;quot;进化&amp;quot;仍在进行中——AGPL-3.0 许可证意味着衍生项目可以在此基础上继续扩展，而 3.7M 行的 Python 代码量也意味着维护成本不低。&lt;/p&gt;
&lt;p&gt;对于想学习注册工具架构设计、支付协议逆向、或者浏览器自动化实战的开发者，这个项目是一个非常有价值的参考案例。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文基于 2026 年 6 月 1 日的仓库状态分析。项目仍在快速迭代中，部分细节可能已有更新。&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>