<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Cloudflare on Tarragon</title><link>https://tarrragon.github.io/blog/tags/cloudflare/</link><description>Recent content in Cloudflare on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 17 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/cloudflare/index.xml" rel="self" type="application/rss+xml"/><item><title>Cloudflare 2019 Regex CPU Outage</title><link>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/</guid><description>&lt;p>2019 年 Cloudflare regex 事故的核心教訓是：控制面配置錯誤可以在秒級擴散成全球可用性事故。這類事故的第一責任不是「加機器」，而是迅速切斷擴散路徑，讓錯誤停止被新流量放大。&lt;/p>
&lt;h2 id="事故摘要">事故摘要&lt;/h2>
&lt;p>Cloudflare 在 2019-07-02 發布新的 WAF Managed Rule 後，規則中的 regex 觸發 catastrophic backtracking，導致 edge CPU 快速打滿。事故影響約 27 分鐘，症狀是大量 502/503 與延遲激增。&lt;/p>
&lt;p>這起事件屬於典型「控制面配置推送 → data plane 全網受影響」模式。錯誤並非單點節點故障，而是由一致推送機制把同一錯誤同步擴散到整個 edge 網路。&lt;/p>
&lt;h2 id="判讀訊號">判讀訊號&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>事故中代表什麼&lt;/th>
 &lt;th>第一波決策價值&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>全球 CPU 同步飆升&lt;/td>
 &lt;td>問題來自共用規則或共用執行路徑&lt;/td>
 &lt;td>優先檢查最新全域配置變更&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>5xx 與延遲同時惡化&lt;/td>
 &lt;td>非單純容量尖峰，更像執行成本突增&lt;/td>
 &lt;td>優先撤回新規則，避免持續放大&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多區域同時報警&lt;/td>
 &lt;td>事故已跨區域，屬全網級控制面風險&lt;/td>
 &lt;td>啟動全域指揮節奏與高頻通訊&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>回滾後指標快速回穩&lt;/td>
 &lt;td>根因與近期變更高度相關&lt;/td>
 &lt;td>立即凍結同批規則推送，改走分區驗證&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>事件期間 rule path 命中異常增&lt;/td>
 &lt;td>單一規則造成 CPU 熱點&lt;/td>
 &lt;td>補 rule-level profiling 與上線前成本檢查&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="事故路徑">事故路徑&lt;/h2>
&lt;ol>
&lt;li>控制面推送新 WAF 規則到全球 edge。&lt;/li>
&lt;li>規則 regex 在特定輸入下產生高計算成本。&lt;/li>
&lt;li>edge CPU 被規則執行成本吃滿，請求處理能力下降。&lt;/li>
&lt;li>5xx 與延遲擴散成全球可見症狀。&lt;/li>
&lt;li>回滾規則後，CPU 與可用性逐步恢復。&lt;/li>
&lt;/ol>
&lt;p>這條路徑顯示：事故擴散速度主要由「推送覆蓋範圍」決定，而不是由「單機故障率」決定。&lt;/p>
&lt;h2 id="可回寫控制面">可回寫控制面&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>控制面&lt;/th>
 &lt;th>這次事故暴露的缺口&lt;/th>
 &lt;th>回寫方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>規則上線前靜態檢查&lt;/td>
 &lt;td>regex 風險模式未被擋下&lt;/td>
 &lt;td>補 regex 風險 lint 與拒絕規則（高 backtracking 風險直接阻擋）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>上線前效能測試&lt;/td>
 &lt;td>缺少 rule-level CPU 成本基線&lt;/td>
 &lt;td>補 rule replay 測試，用代表性 payload 驗證執行成本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>推送策略&lt;/td>
 &lt;td>全域一次推送讓 blast radius 過大&lt;/td>
 &lt;td>改成分區/分群 staged rollout，設回滾閘門&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>事故啟動門檻&lt;/td>
 &lt;td>全網症狀出現後才完整升級&lt;/td>
 &lt;td>以「跨區 CPU 同步異常 + 5xx 上升」作為自動升級條件&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Decision log&lt;/td>
 &lt;td>事中決策若缺時間線，復盤成本高&lt;/td>
 &lt;td>在事故期間即時記錄假設、回滾條件、責任人與驗證結果&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Evidence write-back&lt;/td>
 &lt;td>事故教訓易停在 PIR 文本&lt;/td>
 &lt;td>回寫到 &lt;code>04&lt;/code> 觀測規則與 &lt;code>06&lt;/code> 實驗安全邊界，形成下次推送前硬性 gate&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>回寫訊號治理： &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/telemetry-data-quality/" data-link-title="4.17 Telemetry Data Quality" data-link-desc="把 missing signal、schema drift、sampling bias 與 timestamp skew 變成資料品質問題">4.17 Telemetry Data Quality&lt;/a>&lt;/li>
&lt;li>回寫規則成本訊號： &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/rule-level-cpu-signal-governance/" data-link-title="4.21 Rule-level CPU Signal Governance" data-link-desc="把規則與策略執行成本變成可觀測訊號，避免控制面小變更在資料面形成 CPU 熱點。">4.21 Rule-level CPU Signal Governance&lt;/a>&lt;/li>
&lt;li>回寫規則推送閘門： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate&lt;/a>&lt;/li>
&lt;li>回寫驗證與安全邊界： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/experiment-safety-boundary/" data-link-title="6.20 Experiment Safety Boundary" data-link-desc="定義 chaos、load test、DR drill 的 [blast radius](/backend/knowledge-cards/blast-radius/)、停止條件與權限約束">6.20 Experiment Safety Boundary&lt;/a>&lt;/li>
&lt;li>回寫事中決策與證據： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log&lt;/a>&lt;/li>
&lt;li>回寫跨模組閉環： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="引用源">引用源&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019">Details of the Cloudflare outage on July 2, 2019&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>2019 年 Cloudflare regex 事故的核心教訓是：控制面配置錯誤可以在秒級擴散成全球可用性事故。這類事故的第一責任不是「加機器」，而是迅速切斷擴散路徑，讓錯誤停止被新流量放大。</p>
<h2 id="事故摘要">事故摘要</h2>
<p>Cloudflare 在 2019-07-02 發布新的 WAF Managed Rule 後，規則中的 regex 觸發 catastrophic backtracking，導致 edge CPU 快速打滿。事故影響約 27 分鐘，症狀是大量 502/503 與延遲激增。</p>
<p>這起事件屬於典型「控制面配置推送 → data plane 全網受影響」模式。錯誤並非單點節點故障，而是由一致推送機制把同一錯誤同步擴散到整個 edge 網路。</p>
<h2 id="判讀訊號">判讀訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>事故中代表什麼</th>
          <th>第一波決策價值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>全球 CPU 同步飆升</td>
          <td>問題來自共用規則或共用執行路徑</td>
          <td>優先檢查最新全域配置變更</td>
      </tr>
      <tr>
          <td>5xx 與延遲同時惡化</td>
          <td>非單純容量尖峰，更像執行成本突增</td>
          <td>優先撤回新規則，避免持續放大</td>
      </tr>
      <tr>
          <td>多區域同時報警</td>
          <td>事故已跨區域，屬全網級控制面風險</td>
          <td>啟動全域指揮節奏與高頻通訊</td>
      </tr>
      <tr>
          <td>回滾後指標快速回穩</td>
          <td>根因與近期變更高度相關</td>
          <td>立即凍結同批規則推送，改走分區驗證</td>
      </tr>
      <tr>
          <td>事件期間 rule path 命中異常增</td>
          <td>單一規則造成 CPU 熱點</td>
          <td>補 rule-level profiling 與上線前成本檢查</td>
      </tr>
  </tbody>
</table>
<h2 id="事故路徑">事故路徑</h2>
<ol>
<li>控制面推送新 WAF 規則到全球 edge。</li>
<li>規則 regex 在特定輸入下產生高計算成本。</li>
<li>edge CPU 被規則執行成本吃滿，請求處理能力下降。</li>
<li>5xx 與延遲擴散成全球可見症狀。</li>
<li>回滾規則後，CPU 與可用性逐步恢復。</li>
</ol>
<p>這條路徑顯示：事故擴散速度主要由「推送覆蓋範圍」決定，而不是由「單機故障率」決定。</p>
<h2 id="可回寫控制面">可回寫控制面</h2>
<table>
  <thead>
      <tr>
          <th>控制面</th>
          <th>這次事故暴露的缺口</th>
          <th>回寫方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>規則上線前靜態檢查</td>
          <td>regex 風險模式未被擋下</td>
          <td>補 regex 風險 lint 與拒絕規則（高 backtracking 風險直接阻擋）</td>
      </tr>
      <tr>
          <td>上線前效能測試</td>
          <td>缺少 rule-level CPU 成本基線</td>
          <td>補 rule replay 測試，用代表性 payload 驗證執行成本</td>
      </tr>
      <tr>
          <td>推送策略</td>
          <td>全域一次推送讓 blast radius 過大</td>
          <td>改成分區/分群 staged rollout，設回滾閘門</td>
      </tr>
      <tr>
          <td>事故啟動門檻</td>
          <td>全網症狀出現後才完整升級</td>
          <td>以「跨區 CPU 同步異常 + 5xx 上升」作為自動升級條件</td>
      </tr>
      <tr>
          <td>Decision log</td>
          <td>事中決策若缺時間線，復盤成本高</td>
          <td>在事故期間即時記錄假設、回滾條件、責任人與驗證結果</td>
      </tr>
      <tr>
          <td>Evidence write-back</td>
          <td>事故教訓易停在 PIR 文本</td>
          <td>回寫到 <code>04</code> 觀測規則與 <code>06</code> 實驗安全邊界，形成下次推送前硬性 gate</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>回寫訊號治理： <a href="/blog/backend/04-observability/telemetry-data-quality/" data-link-title="4.17 Telemetry Data Quality" data-link-desc="把 missing signal、schema drift、sampling bias 與 timestamp skew 變成資料品質問題">4.17 Telemetry Data Quality</a></li>
<li>回寫規則成本訊號： <a href="/blog/backend/04-observability/rule-level-cpu-signal-governance/" data-link-title="4.21 Rule-level CPU Signal Governance" data-link-desc="把規則與策略執行成本變成可觀測訊號，避免控制面小變更在資料面形成 CPU 熱點。">4.21 Rule-level CPU Signal Governance</a></li>
<li>回寫規則推送閘門： <a href="/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate</a></li>
<li>回寫驗證與安全邊界： <a href="/blog/backend/06-reliability/experiment-safety-boundary/" data-link-title="6.20 Experiment Safety Boundary" data-link-desc="定義 chaos、load test、DR drill 的 [blast radius](/backend/knowledge-cards/blast-radius/)、停止條件與權限約束">6.20 Experiment Safety Boundary</a></li>
<li>回寫事中決策與證據： <a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log</a></li>
<li>回寫跨模組閉環： <a href="/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back</a></li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019">Details of the Cloudflare outage on July 2, 2019</a></li>
</ul>
]]></content:encoded></item><item><title>Cloudflare 2023 Control Plane Token Incident</title><link>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/</guid><description>&lt;p>2023 年 Cloudflare control-plane 事故的核心教訓是：身份與憑證類變更一旦跨產品共用，單點錯誤會變成系統級連鎖故障。這類事故要先切的是信任邊界，不是先做流量微調。&lt;/p>
&lt;h2 id="事故摘要">事故摘要&lt;/h2>
&lt;p>Cloudflare 在 2023-01-24 經歷 service token 相關變更問題，造成內外部控制面能力受影響，連帶影響多個產品面向。事件本質是控制面身份機制失效，並透過共用依賴擴散。&lt;/p>
&lt;p>這類事故的危險在於症狀看起來像多個服務同時不穩，但根因其實是同一個共享身份控制點。若沒有先識別 shared dependency，排障會被切成很多局部問題，恢復速度會顯著下降。&lt;/p>
&lt;h2 id="判讀訊號">判讀訊號&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>事故中代表什麼&lt;/th>
 &lt;th>第一波決策價值&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>多產品同時出現驗證/授權異常&lt;/td>
 &lt;td>共享身份或憑證控制點可能失效&lt;/td>
 &lt;td>優先檢查 token / policy 最新變更&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>失敗集中在控制面 API&lt;/td>
 &lt;td>問題偏向控制面，不是資料面容量瓶頸&lt;/td>
 &lt;td>啟動控制面優先處理，不先做業務層調參&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>局部回復但整體仍不穩&lt;/td>
 &lt;td>依賴鏈條有殘留錯誤狀態&lt;/td>
 &lt;td>補 dependency-by-dependency 驗證清單&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>回退後錯誤快速下降&lt;/td>
 &lt;td>變更與故障關聯度高&lt;/td>
 &lt;td>立即凍結同批身份變更與關聯部署&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>事故中責任邊界模糊&lt;/td>
 &lt;td>ownership 與交接規則不足&lt;/td>
 &lt;td>指派 single incident owner 與決策記錄&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="事故路徑">事故路徑&lt;/h2>
&lt;ol>
&lt;li>控制面 token/身份相關變更進入生產環境。&lt;/li>
&lt;li>共享身份依賴開始出現授權或驗證失效。&lt;/li>
&lt;li>多個產品面的控制操作受阻，形成連鎖症狀。&lt;/li>
&lt;li>團隊透過回退與修正策略逐步收斂。&lt;/li>
&lt;li>事件後需回寫身份變更治理與事故交接流程。&lt;/li>
&lt;/ol>
&lt;p>這條路徑顯示：擴散關鍵在 shared identity dependency，不在單一產品流量高低。&lt;/p>
&lt;h2 id="可回寫控制面">可回寫控制面&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>控制面&lt;/th>
 &lt;th>這次事故暴露的缺口&lt;/th>
 &lt;th>回寫方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>身份變更審核&lt;/td>
 &lt;td>token/policy 變更前缺少跨產品影響分析&lt;/td>
 &lt;td>補 shared dependency impact checklist&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>發布策略&lt;/td>
 &lt;td>身份控制面變更缺少逐層 rollout&lt;/td>
 &lt;td>先低風險範圍啟用，再逐步擴大&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>事故啟動條件&lt;/td>
 &lt;td>多產品異常時未即時指向 shared root&lt;/td>
 &lt;td>新增「多產品授權異常」的快速升級條件&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Decision log&lt;/td>
 &lt;td>假設、回退條件與責任分工不夠明確&lt;/td>
 &lt;td>事中強制記錄假設、證據、回退門檻與 owner&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Evidence write-back&lt;/td>
 &lt;td>教訓停在事件敘述&lt;/td>
 &lt;td>回寫 &lt;code>07&lt;/code> 身分邊界治理、&lt;code>08&lt;/code> decision log、&lt;code>04&lt;/code> 控制面健康訊號&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Handoff protocol&lt;/td>
 &lt;td>長事故交接易遺失上下文&lt;/td>
 &lt;td>使用固定 handoff 模板，包含當前假設、已驗證路徑、未完成風險與下一步責任&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>身分邊界與權限治理： &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">7.2 Identity Access Boundary&lt;/a>&lt;/li>
&lt;li>規則推送安全閘門： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate&lt;/a>&lt;/li>
&lt;li>事故決策紀錄： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log&lt;/a>&lt;/li>
&lt;li>證據回寫流程： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back&lt;/a>&lt;/li>
&lt;li>控制面訊號治理： &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/observability-operating-model/" data-link-title="4.18 Observability Operating Model" data-link-desc="定義 platform / service team / on-call 對訊號、dashboard、alert 與成本的 ownership">4.18 Observability Operating Model&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="引用源">引用源&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.cloudflare.com/cloudflare-incident-on-january-24th-2023/">Cloudflare incident on January 24, 2023&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>2023 年 Cloudflare control-plane 事故的核心教訓是：身份與憑證類變更一旦跨產品共用，單點錯誤會變成系統級連鎖故障。這類事故要先切的是信任邊界，不是先做流量微調。</p>
<h2 id="事故摘要">事故摘要</h2>
<p>Cloudflare 在 2023-01-24 經歷 service token 相關變更問題，造成內外部控制面能力受影響，連帶影響多個產品面向。事件本質是控制面身份機制失效，並透過共用依賴擴散。</p>
<p>這類事故的危險在於症狀看起來像多個服務同時不穩，但根因其實是同一個共享身份控制點。若沒有先識別 shared dependency，排障會被切成很多局部問題，恢復速度會顯著下降。</p>
<h2 id="判讀訊號">判讀訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>事故中代表什麼</th>
          <th>第一波決策價值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>多產品同時出現驗證/授權異常</td>
          <td>共享身份或憑證控制點可能失效</td>
          <td>優先檢查 token / policy 最新變更</td>
      </tr>
      <tr>
          <td>失敗集中在控制面 API</td>
          <td>問題偏向控制面，不是資料面容量瓶頸</td>
          <td>啟動控制面優先處理，不先做業務層調參</td>
      </tr>
      <tr>
          <td>局部回復但整體仍不穩</td>
          <td>依賴鏈條有殘留錯誤狀態</td>
          <td>補 dependency-by-dependency 驗證清單</td>
      </tr>
      <tr>
          <td>回退後錯誤快速下降</td>
          <td>變更與故障關聯度高</td>
          <td>立即凍結同批身份變更與關聯部署</td>
      </tr>
      <tr>
          <td>事故中責任邊界模糊</td>
          <td>ownership 與交接規則不足</td>
          <td>指派 single incident owner 與決策記錄</td>
      </tr>
  </tbody>
</table>
<h2 id="事故路徑">事故路徑</h2>
<ol>
<li>控制面 token/身份相關變更進入生產環境。</li>
<li>共享身份依賴開始出現授權或驗證失效。</li>
<li>多個產品面的控制操作受阻，形成連鎖症狀。</li>
<li>團隊透過回退與修正策略逐步收斂。</li>
<li>事件後需回寫身份變更治理與事故交接流程。</li>
</ol>
<p>這條路徑顯示：擴散關鍵在 shared identity dependency，不在單一產品流量高低。</p>
<h2 id="可回寫控制面">可回寫控制面</h2>
<table>
  <thead>
      <tr>
          <th>控制面</th>
          <th>這次事故暴露的缺口</th>
          <th>回寫方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>身份變更審核</td>
          <td>token/policy 變更前缺少跨產品影響分析</td>
          <td>補 shared dependency impact checklist</td>
      </tr>
      <tr>
          <td>發布策略</td>
          <td>身份控制面變更缺少逐層 rollout</td>
          <td>先低風險範圍啟用，再逐步擴大</td>
      </tr>
      <tr>
          <td>事故啟動條件</td>
          <td>多產品異常時未即時指向 shared root</td>
          <td>新增「多產品授權異常」的快速升級條件</td>
      </tr>
      <tr>
          <td>Decision log</td>
          <td>假設、回退條件與責任分工不夠明確</td>
          <td>事中強制記錄假設、證據、回退門檻與 owner</td>
      </tr>
      <tr>
          <td>Evidence write-back</td>
          <td>教訓停在事件敘述</td>
          <td>回寫 <code>07</code> 身分邊界治理、<code>08</code> decision log、<code>04</code> 控制面健康訊號</td>
      </tr>
      <tr>
          <td>Handoff protocol</td>
          <td>長事故交接易遺失上下文</td>
          <td>使用固定 handoff 模板，包含當前假設、已驗證路徑、未完成風險與下一步責任</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>身分邊界與權限治理： <a href="/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">7.2 Identity Access Boundary</a></li>
<li>規則推送安全閘門： <a href="/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate</a></li>
<li>事故決策紀錄： <a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log</a></li>
<li>證據回寫流程： <a href="/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back</a></li>
<li>控制面訊號治理： <a href="/blog/backend/04-observability/observability-operating-model/" data-link-title="4.18 Observability Operating Model" data-link-desc="定義 platform / service team / on-call 對訊號、dashboard、alert 與成本的 ownership">4.18 Observability Operating Model</a></li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://blog.cloudflare.com/cloudflare-incident-on-january-24th-2023/">Cloudflare incident on January 24, 2023</a></li>
</ul>
]]></content:encoded></item><item><title>Cloudflare</title><link>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/</link><pubDate>Fri, 01 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/</guid><description>&lt;p>Cloudflare 是 anycast edge 的代表、單一配置 push 即可影響全球流量、是 configuration push 風險 / regex catastrophic backtracking / BGP 信任的教學標竿。Cloudflare 工程部落格公開度極高、post-mortem 細節豐富。&lt;/p>
&lt;h2 id="規劃重點">規劃重點&lt;/h2>
&lt;ul>
&lt;li>全球 configuration push 的 blast radius：為何 60 秒內可癱瘓全球流量&lt;/li>
&lt;li>Regex CPU 耗盡：catastrophic backtracking 如何繞過所有 timeout&lt;/li>
&lt;li>BGP 風險：路由洩漏如何把流量吸入錯誤 ASN&lt;/li>
&lt;li>Recovery 設計：為何 configuration rollback 需要 dataplane 層協作&lt;/li>
&lt;/ul>
&lt;h2 id="預計收錄事故">預計收錄事故&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>年份&lt;/th>
 &lt;th>事故&lt;/th>
 &lt;th>教學重點&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>2019&lt;/td>
 &lt;td>Regex CPU 27 分鐘&lt;/td>
 &lt;td>catastrophic backtracking、WAF rule 部署流程&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>2020&lt;/td>
 &lt;td>BGP route leak&lt;/td>
 &lt;td>跨 ASN 信任、網路層事故止血&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>2022&lt;/td>
 &lt;td>配置 push 全球退化&lt;/td>
 &lt;td>變更節奏、staged rollout 的價值&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>2023&lt;/td>
 &lt;td>Control plane token incident&lt;/td>
 &lt;td>身分控制面與多產品連鎖影響&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>2026&lt;/td>
 &lt;td>BYOIP / BGP withdrawal&lt;/td>
 &lt;td>Addressing API、prefix withdrawal、狀態恢復&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="案例清單">案例清單&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/" data-link-title="Cloudflare 2019 Regex CPU Outage" data-link-desc="2019-07-02 Cloudflare WAF 規則更新導致全球 CPU 飆升的事故解析：觸發條件、擴散機制、止血決策與可回寫控制面。">2019 Regex CPU Outage&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/" data-link-title="Cloudflare 2023 Control Plane Token Incident" data-link-desc="2023-01-24 Cloudflare service token 錯誤變更導致多產品連鎖影響的事故解析：信任邊界、擴散機制、止血策略與流程回寫。">2023 Control Plane Token Incident&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/" data-link-title="Cloudflare 2023 Workers KV Deployment Tool Misconfiguration" data-link-desc="2023-10-30 Cloudflare 控制面事故：deployment tool 設定錯誤造成 Workers KV 連鎖影響，重點在變更範圍限制與決策回寫。">2023 Workers KV Deployment Tool Misconfiguration&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/" data-link-title="Cloudflare 2026 BYOIP BGP Withdrawal" data-link-desc="2026-02-20 Cloudflare BYOIP prefixes 被非預期撤告的事故解析：Addressing API bug、BGP withdrawal、狀態恢復與控制面回寫。">2026 BYOIP BGP Withdrawal&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="建議閱讀順序">建議閱讀順序&lt;/h2>
&lt;ol>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/" data-link-title="Cloudflare 2019 Regex CPU Outage" data-link-desc="2019-07-02 Cloudflare WAF 規則更新導致全球 CPU 飆升的事故解析：觸發條件、擴散機制、止血決策與可回寫控制面。">2019 Regex CPU Outage&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/" data-link-title="Cloudflare 2023 Control Plane Token Incident" data-link-desc="2023-01-24 Cloudflare service token 錯誤變更導致多產品連鎖影響的事故解析：信任邊界、擴散機制、止血策略與流程回寫。">2023 Control Plane Token Incident&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/" data-link-title="Cloudflare 2023 Workers KV Deployment Tool Misconfiguration" data-link-desc="2023-10-30 Cloudflare 控制面事故：deployment tool 設定錯誤造成 Workers KV 連鎖影響，重點在變更範圍限制與決策回寫。">2023 Workers KV Deployment Tool Misconfiguration&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/" data-link-title="Cloudflare 2026 BYOIP BGP Withdrawal" data-link-desc="2026-02-20 Cloudflare BYOIP prefixes 被非預期撤告的事故解析：Addressing API bug、BGP withdrawal、狀態恢復與控制面回寫。">2026 BYOIP BGP Withdrawal&lt;/a>&lt;/li>
&lt;/ol>
&lt;h2 id="案例定位">案例定位&lt;/h2>
&lt;p>Cloudflare 這個案例在講的是 edge 平台如何把一個小錯誤快速放大到全球。讀者先看懂配置推送、runtime 驗證與路由撤銷各自的責任，再把 anycast 與 control plane 當成事故擴散的核心路徑。&lt;/p></description><content:encoded><![CDATA[<p>Cloudflare 是 anycast edge 的代表、單一配置 push 即可影響全球流量、是 configuration push 風險 / regex catastrophic backtracking / BGP 信任的教學標竿。Cloudflare 工程部落格公開度極高、post-mortem 細節豐富。</p>
<h2 id="規劃重點">規劃重點</h2>
<ul>
<li>全球 configuration push 的 blast radius：為何 60 秒內可癱瘓全球流量</li>
<li>Regex CPU 耗盡：catastrophic backtracking 如何繞過所有 timeout</li>
<li>BGP 風險：路由洩漏如何把流量吸入錯誤 ASN</li>
<li>Recovery 設計：為何 configuration rollback 需要 dataplane 層協作</li>
</ul>
<h2 id="預計收錄事故">預計收錄事故</h2>
<table>
  <thead>
      <tr>
          <th>年份</th>
          <th>事故</th>
          <th>教學重點</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>2019</td>
          <td>Regex CPU 27 分鐘</td>
          <td>catastrophic backtracking、WAF rule 部署流程</td>
      </tr>
      <tr>
          <td>2020</td>
          <td>BGP route leak</td>
          <td>跨 ASN 信任、網路層事故止血</td>
      </tr>
      <tr>
          <td>2022</td>
          <td>配置 push 全球退化</td>
          <td>變更節奏、staged rollout 的價值</td>
      </tr>
      <tr>
          <td>2023</td>
          <td>Control plane token incident</td>
          <td>身分控制面與多產品連鎖影響</td>
      </tr>
      <tr>
          <td>2026</td>
          <td>BYOIP / BGP withdrawal</td>
          <td>Addressing API、prefix withdrawal、狀態恢復</td>
      </tr>
  </tbody>
</table>
<h2 id="案例清單">案例清單</h2>
<ul>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/" data-link-title="Cloudflare 2019 Regex CPU Outage" data-link-desc="2019-07-02 Cloudflare WAF 規則更新導致全球 CPU 飆升的事故解析：觸發條件、擴散機制、止血決策與可回寫控制面。">2019 Regex CPU Outage</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/" data-link-title="Cloudflare 2023 Control Plane Token Incident" data-link-desc="2023-01-24 Cloudflare service token 錯誤變更導致多產品連鎖影響的事故解析：信任邊界、擴散機制、止血策略與流程回寫。">2023 Control Plane Token Incident</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/" data-link-title="Cloudflare 2023 Workers KV Deployment Tool Misconfiguration" data-link-desc="2023-10-30 Cloudflare 控制面事故：deployment tool 設定錯誤造成 Workers KV 連鎖影響，重點在變更範圍限制與決策回寫。">2023 Workers KV Deployment Tool Misconfiguration</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/" data-link-title="Cloudflare 2026 BYOIP BGP Withdrawal" data-link-desc="2026-02-20 Cloudflare BYOIP prefixes 被非預期撤告的事故解析：Addressing API bug、BGP withdrawal、狀態恢復與控制面回寫。">2026 BYOIP BGP Withdrawal</a></li>
</ul>
<h2 id="建議閱讀順序">建議閱讀順序</h2>
<ol>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2019-regex-cpu-outage/" data-link-title="Cloudflare 2019 Regex CPU Outage" data-link-desc="2019-07-02 Cloudflare WAF 規則更新導致全球 CPU 飆升的事故解析：觸發條件、擴散機制、止血決策與可回寫控制面。">2019 Regex CPU Outage</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2023-control-plane-token-incident/" data-link-title="Cloudflare 2023 Control Plane Token Incident" data-link-desc="2023-01-24 Cloudflare service token 錯誤變更導致多產品連鎖影響的事故解析：信任邊界、擴散機制、止血策略與流程回寫。">2023 Control Plane Token Incident</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/" data-link-title="Cloudflare 2023 Workers KV Deployment Tool Misconfiguration" data-link-desc="2023-10-30 Cloudflare 控制面事故：deployment tool 設定錯誤造成 Workers KV 連鎖影響，重點在變更範圍限制與決策回寫。">2023 Workers KV Deployment Tool Misconfiguration</a></li>
<li><a href="/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/" data-link-title="Cloudflare 2026 BYOIP BGP Withdrawal" data-link-desc="2026-02-20 Cloudflare BYOIP prefixes 被非預期撤告的事故解析：Addressing API bug、BGP withdrawal、狀態恢復與控制面回寫。">2026 BYOIP BGP Withdrawal</a></li>
</ol>
<h2 id="案例定位">案例定位</h2>
<p>Cloudflare 這個案例在講的是 edge 平台如何把一個小錯誤快速放大到全球。讀者先看懂配置推送、runtime 驗證與路由撤銷各自的責任，再把 anycast 與 control plane 當成事故擴散的核心路徑。</p>
<h2 id="判讀重點">判讀重點</h2>
<p>當 regex、workers 設定或 deployment tool 出現問題時，真正危險的是錯誤被快速推到全網，單一節點故障反而容易收斂。當 BGP 或 BYOIP 參數變動時，回滾與驗證就必須先於擴散，否則影響會直接表現在全球流量上。</p>
<h2 id="可操作判準">可操作判準</h2>
<ul>
<li>能否在全網推送前做足夠的配置驗證</li>
<li>能否把 blast radius 限制在局部 edge 群組</li>
<li>能否在 CPU 熱點或路由撤銷前先看見異常</li>
<li>能否把 rollback 動作設計成快速且可驗證</li>
</ul>
<h2 id="與其他案例的關係">與其他案例的關係</h2>
<p>Cloudflare 和 Fastly 都在講 edge 平台的快速擴散，但 Cloudflare 更常暴露控制面與部署工具的問題。它和 AWS S3、GCP 放在一起看，可以更清楚看到全球網路事故是配置與路由鏈條的連鎖反應，單一節點失效很少是起因。</p>
<h2 id="代表樣本">代表樣本</h2>
<ul>
<li>2019 年 regex CPU outage 是 catastrophic backtracking 直接拖垮 edge runtime 的經典樣本。</li>
<li>2023 年控制面事故與 2026 年 BYOIP / BGP 事故則顯示配置與路由都能成為全球擴散點。</li>
<li>這組樣本也能對照配置推送與回滾速度對 blast radius 的影響。</li>
<li>Cloudflare 的事故史很適合拿來和 Fastly 比較 edge 平台差異。</li>
<li>workers / deployment tool misconfiguration 讓控制面本身成為風險。</li>
<li>anycast edge 讓路由錯誤能在全球尺度迅速顯現。</li>
<li>global propagation 讓回滾時間直接影響用戶體感。</li>
<li>control plane bug 常常比 data plane bug 更難局部化。</li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019">Details of the Cloudflare outage on July 2, 2019</a>：regex CPU / catastrophic backtracking 事故的官方回顧。</li>
<li><a href="https://blog.cloudflare.com/cloudflare-incident-on-january-24th-2023/">Cloudflare incident on January 24, 2023</a>：service token / control plane 變更導致的多產品連鎖影響。</li>
<li><a href="https://blog.cloudflare.com/cloudflare-incident-on-october-30-2023/">Cloudflare incident on October 30, 2023</a>：Workers KV / deployment tool misconfiguration 的控制面事故。</li>
<li><a href="https://blog.cloudflare.com/cloudflare-outage-february-20-2026/">Cloudflare outage on February 20, 2026</a>：BYOIP / BGP 變更造成的路由撤銷事故。</li>
</ul>
]]></content:encoded></item><item><title>Cloudflare 2026 BYOIP BGP Withdrawal</title><link>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2026-byoip-bgp-withdrawal/</guid><description>&lt;p>2026 年 Cloudflare BYOIP / BGP 事故的核心教訓是：控制面資料一旦同時承擔 customer configuration 與 operational state，錯誤清理流程會直接變成全網路由變更。這類事故的第一責任是停止錯誤狀態傳播，再把 desired state 與 actual state 拆開恢復。&lt;/p>
&lt;h2 id="事故摘要">事故摘要&lt;/h2>
&lt;p>Cloudflare 在 2026-02-20 17:48 UTC 發生 BYOIP 相關 outage。部分使用 Bring Your Own IP（BYOIP）的客戶，其 IP prefixes 被 Cloudflare 經由 BGP 非預期撤告，導致相關服務從 Internet 無法到達。官方回顧指出，事故總時長為 6 小時 7 分鐘；在 4,306 個 BYOIP prefixes 中，約 1,100 個 prefixes 曾被撤告，約佔 BYOIP prefixes 的 25%。&lt;/p>
&lt;p>事故起因是 Cloudflare 在 Addressing API / BYOIP pipeline 中引入的自動化清理流程，與外部攻擊無關。該流程原本要移除 pending deletion 的 prefixes，但 API query 的 &lt;code>pending_delete&lt;/code> 參數沒有值，server 端將它解讀成一般查詢，回傳所有 BYOIP prefixes。下游流程接著把回傳結果當成待刪除集合，開始撤告 prefixes 與移除相關 service bindings。&lt;/p>
&lt;h2 id="判讀訊號">判讀訊號&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>事故中代表什麼&lt;/th>
 &lt;th>第一波決策價值&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>BYOIP prefixes 數量快速下降&lt;/td>
 &lt;td>BGP advertisement 正在被控制面錯誤改寫&lt;/td>
 &lt;td>立即停止最新 Addressing API / cleanup 任務&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>客戶服務從 Internet 無法連線&lt;/td>
 &lt;td>prefix withdrawal 已影響資料面可達性&lt;/td>
 &lt;td>優先恢復 prefix advertisement，而非只查應用層錯誤&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>部分客戶可自行 re-advertise&lt;/td>
 &lt;td>部分狀態只被撤告，binding 尚未被刪除&lt;/td>
 &lt;td>對外提供 dashboard workaround，降低待處理影響面&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>部分客戶無法自助恢復&lt;/td>
 &lt;td>service bindings 或 edge 設定也被移除&lt;/td>
 &lt;td>需要工程團隊做資料恢復與 global configuration rollout&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>恢復分成多批完成&lt;/td>
 &lt;td>受影響 prefixes 處於不同損壞狀態&lt;/td>
 &lt;td>decision log 要分別記錄「可自助」「需手動」「需全域 rollout」&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="事故路徑">事故路徑&lt;/h2>
&lt;ol>
&lt;li>Addressing API 相關程式碼在 2026-02-05 合併，並於 2026-02-20 部署。&lt;/li>
&lt;li>cleanup sub-task 查詢 &lt;code>/v1/prefixes?pending_delete&lt;/code>，但 &lt;code>pending_delete&lt;/code> 沒有值。&lt;/li>
&lt;li>API server 沒有進入 pending deletion 分支，而是回傳所有 BYOIP prefixes。&lt;/li>
&lt;li>cleanup sub-task 將回傳的 prefixes 解讀成待移除集合，開始撤告 prefixes 與刪除 dependent objects。&lt;/li>
&lt;li>Cloudflare 在觀察到 1.1.1.1 相關失敗後回退變更並終止 broken sub-process。&lt;/li>
&lt;li>多數 prefixes 透過 re-advertise 或 restore 流程恢復，剩餘約 300 個 prefixes 需要工程師手動恢復 service bindings 與 edge 設定。&lt;/li>
&lt;/ol>
&lt;p>這條路徑顯示：BGP withdrawal 是結果，真正的事故起點是控制面資料查詢語意不明確，以及 operational workflow 對查詢結果缺少大範圍變更 circuit breaker。&lt;/p>
&lt;h2 id="可回寫控制面">可回寫控制面&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>控制面&lt;/th>
 &lt;th>這次事故暴露的缺口&lt;/th>
 &lt;th>回寫方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>API schema&lt;/td>
 &lt;td>boolean-like query 參數語意不明確&lt;/td>
 &lt;td>將狀態查詢參數標準化，錯誤或空值直接拒絕，不進入危險預設路徑&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Desired / actual state 分離&lt;/td>
 &lt;td>customer configuration 與 operational action 混在同一資料面&lt;/td>
 &lt;td>引入 snapshot / staged deployment，讓壞資料可快速回到 known-good state&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>大範圍 withdrawal circuit breaker&lt;/td>
 &lt;td>cleanup 任務可一次影響大量 prefixes&lt;/td>
 &lt;td>對 prefix withdrawal / deletion 設速率、數量與健康訊號閘門&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Staging 與 mock data&lt;/td>
 &lt;td>測試資料未覆蓋 task-runner 自主操作情境&lt;/td>
 &lt;td>補 production-like state mutation 測試，而不只測 customer journey&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Incident intake&lt;/td>
 &lt;td>1.1.1.1 異常成為早期觀察點&lt;/td>
 &lt;td>將共享基礎服務異常納入控制面事故快速升級條件&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Evidence write-back&lt;/td>
 &lt;td>恢復分成 dashboard 自助、資料修復、global rollout 多條路&lt;/td>
 &lt;td>回寫 decision log 與 evidence package，保留每種狀態的恢復判準&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>控制面資料品質： &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/telemetry-data-quality/" data-link-title="4.17 Telemetry Data Quality" data-link-desc="把 missing signal、schema drift、sampling bias 與 timestamp skew 變成資料品質問題">4.17 Telemetry Data Quality&lt;/a>&lt;/li>
&lt;li>規則推送安全閘門： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate&lt;/a>&lt;/li>
&lt;li>變更安全邊界： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/experiment-safety-boundary/" data-link-title="6.20 Experiment Safety Boundary" data-link-desc="定義 chaos、load test、DR drill 的 [blast radius](/backend/knowledge-cards/blast-radius/)、停止條件與權限約束">6.20 Experiment Safety Boundary&lt;/a>&lt;/li>
&lt;li>驗證證據交接： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/verification-evidence-handoff/" data-link-title="6.23 Verification Evidence Handoff" data-link-desc="把 SLO、load、chaos、DR 與 readiness 結果包成 release / incident 可用證據">6.23 Verification Evidence Handoff&lt;/a>&lt;/li>
&lt;li>事故決策紀錄： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log&lt;/a>&lt;/li>
&lt;li>證據回寫流程： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="引用源">引用源&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.cloudflare.com/cloudflare-outage-february-20-2026/">Cloudflare outage on February 20, 2026&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>2026 年 Cloudflare BYOIP / BGP 事故的核心教訓是：控制面資料一旦同時承擔 customer configuration 與 operational state，錯誤清理流程會直接變成全網路由變更。這類事故的第一責任是停止錯誤狀態傳播，再把 desired state 與 actual state 拆開恢復。</p>
<h2 id="事故摘要">事故摘要</h2>
<p>Cloudflare 在 2026-02-20 17:48 UTC 發生 BYOIP 相關 outage。部分使用 Bring Your Own IP（BYOIP）的客戶，其 IP prefixes 被 Cloudflare 經由 BGP 非預期撤告，導致相關服務從 Internet 無法到達。官方回顧指出，事故總時長為 6 小時 7 分鐘；在 4,306 個 BYOIP prefixes 中，約 1,100 個 prefixes 曾被撤告，約佔 BYOIP prefixes 的 25%。</p>
<p>事故起因是 Cloudflare 在 Addressing API / BYOIP pipeline 中引入的自動化清理流程，與外部攻擊無關。該流程原本要移除 pending deletion 的 prefixes，但 API query 的 <code>pending_delete</code> 參數沒有值，server 端將它解讀成一般查詢，回傳所有 BYOIP prefixes。下游流程接著把回傳結果當成待刪除集合，開始撤告 prefixes 與移除相關 service bindings。</p>
<h2 id="判讀訊號">判讀訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>事故中代表什麼</th>
          <th>第一波決策價值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BYOIP prefixes 數量快速下降</td>
          <td>BGP advertisement 正在被控制面錯誤改寫</td>
          <td>立即停止最新 Addressing API / cleanup 任務</td>
      </tr>
      <tr>
          <td>客戶服務從 Internet 無法連線</td>
          <td>prefix withdrawal 已影響資料面可達性</td>
          <td>優先恢復 prefix advertisement，而非只查應用層錯誤</td>
      </tr>
      <tr>
          <td>部分客戶可自行 re-advertise</td>
          <td>部分狀態只被撤告，binding 尚未被刪除</td>
          <td>對外提供 dashboard workaround，降低待處理影響面</td>
      </tr>
      <tr>
          <td>部分客戶無法自助恢復</td>
          <td>service bindings 或 edge 設定也被移除</td>
          <td>需要工程團隊做資料恢復與 global configuration rollout</td>
      </tr>
      <tr>
          <td>恢復分成多批完成</td>
          <td>受影響 prefixes 處於不同損壞狀態</td>
          <td>decision log 要分別記錄「可自助」「需手動」「需全域 rollout」</td>
      </tr>
  </tbody>
</table>
<h2 id="事故路徑">事故路徑</h2>
<ol>
<li>Addressing API 相關程式碼在 2026-02-05 合併，並於 2026-02-20 部署。</li>
<li>cleanup sub-task 查詢 <code>/v1/prefixes?pending_delete</code>，但 <code>pending_delete</code> 沒有值。</li>
<li>API server 沒有進入 pending deletion 分支，而是回傳所有 BYOIP prefixes。</li>
<li>cleanup sub-task 將回傳的 prefixes 解讀成待移除集合，開始撤告 prefixes 與刪除 dependent objects。</li>
<li>Cloudflare 在觀察到 1.1.1.1 相關失敗後回退變更並終止 broken sub-process。</li>
<li>多數 prefixes 透過 re-advertise 或 restore 流程恢復，剩餘約 300 個 prefixes 需要工程師手動恢復 service bindings 與 edge 設定。</li>
</ol>
<p>這條路徑顯示：BGP withdrawal 是結果，真正的事故起點是控制面資料查詢語意不明確，以及 operational workflow 對查詢結果缺少大範圍變更 circuit breaker。</p>
<h2 id="可回寫控制面">可回寫控制面</h2>
<table>
  <thead>
      <tr>
          <th>控制面</th>
          <th>這次事故暴露的缺口</th>
          <th>回寫方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>API schema</td>
          <td>boolean-like query 參數語意不明確</td>
          <td>將狀態查詢參數標準化，錯誤或空值直接拒絕，不進入危險預設路徑</td>
      </tr>
      <tr>
          <td>Desired / actual state 分離</td>
          <td>customer configuration 與 operational action 混在同一資料面</td>
          <td>引入 snapshot / staged deployment，讓壞資料可快速回到 known-good state</td>
      </tr>
      <tr>
          <td>大範圍 withdrawal circuit breaker</td>
          <td>cleanup 任務可一次影響大量 prefixes</td>
          <td>對 prefix withdrawal / deletion 設速率、數量與健康訊號閘門</td>
      </tr>
      <tr>
          <td>Staging 與 mock data</td>
          <td>測試資料未覆蓋 task-runner 自主操作情境</td>
          <td>補 production-like state mutation 測試，而不只測 customer journey</td>
      </tr>
      <tr>
          <td>Incident intake</td>
          <td>1.1.1.1 異常成為早期觀察點</td>
          <td>將共享基礎服務異常納入控制面事故快速升級條件</td>
      </tr>
      <tr>
          <td>Evidence write-back</td>
          <td>恢復分成 dashboard 自助、資料修復、global rollout 多條路</td>
          <td>回寫 decision log 與 evidence package，保留每種狀態的恢復判準</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>控制面資料品質： <a href="/blog/backend/04-observability/telemetry-data-quality/" data-link-title="4.17 Telemetry Data Quality" data-link-desc="把 missing signal、schema drift、sampling bias 與 timestamp skew 變成資料品質問題">4.17 Telemetry Data Quality</a></li>
<li>規則推送安全閘門： <a href="/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate</a></li>
<li>變更安全邊界： <a href="/blog/backend/06-reliability/experiment-safety-boundary/" data-link-title="6.20 Experiment Safety Boundary" data-link-desc="定義 chaos、load test、DR drill 的 [blast radius](/backend/knowledge-cards/blast-radius/)、停止條件與權限約束">6.20 Experiment Safety Boundary</a></li>
<li>驗證證據交接： <a href="/blog/backend/06-reliability/verification-evidence-handoff/" data-link-title="6.23 Verification Evidence Handoff" data-link-desc="把 SLO、load、chaos、DR 與 readiness 結果包成 release / incident 可用證據">6.23 Verification Evidence Handoff</a></li>
<li>事故決策紀錄： <a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log</a></li>
<li>證據回寫流程： <a href="/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back</a></li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://blog.cloudflare.com/cloudflare-outage-february-20-2026/">Cloudflare outage on February 20, 2026</a></li>
</ul>
]]></content:encoded></item><item><title>Cloudflare 2023 Workers KV Deployment Tool Misconfiguration</title><link>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/08-incident-response/cases/cloudflare/2023-workers-kv-deployment-tool-misconfiguration/</guid><description>&lt;p>這起事件的核心責任判讀是：控制面工具設定錯誤會跨越產品邊界擴散，事故第一步要先切斷擴散路徑，再做功能修復。若先把症狀拆成多個產品問題，恢復速度會被 shared dependency 拖慢。&lt;/p>
&lt;h2 id="事故摘要">事故摘要&lt;/h2>
&lt;p>Cloudflare 在 2023-10-30 發生控制面相關事故，根因涉及 deployment tool 的設定錯誤，影響 Workers KV 與相關服務操作路徑。表面症狀可出現在多個產品面向，但本質是共享控制面變更帶來的連鎖失效。&lt;/p>
&lt;p>這類事故和單點 runtime bug 不同。關鍵不是「哪個服務先報錯」，而是「哪個共用控制點先失真」。&lt;/p>
&lt;h2 id="判讀訊號">判讀訊號&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>代表意義&lt;/th>
 &lt;th>第一波決策價值&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>多產品控制操作同時不穩&lt;/td>
 &lt;td>shared control dependency 可能失效&lt;/td>
 &lt;td>先盤點同批變更與共用工具&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>功能異常分布不均&lt;/td>
 &lt;td>擴散沿著控制面依賴鏈條走&lt;/td>
 &lt;td>用 dependency map 排定恢復優先順序&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>回退後錯誤率快速下降&lt;/td>
 &lt;td>變更關聯度高&lt;/td>
 &lt;td>凍結同類變更、啟動增量復原&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>事故中角色交接反覆切換&lt;/td>
 &lt;td>ownership 與指揮節奏不足&lt;/td>
 &lt;td>固定 single incident commander 與節點交接&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="事故路徑">事故路徑&lt;/h2>
&lt;ol>
&lt;li>控制面 deployment tool 變更進入生產。&lt;/li>
&lt;li>設定錯誤導致共享控制路徑失真。&lt;/li>
&lt;li>Workers KV 與關聯產品出現控制操作異常。&lt;/li>
&lt;li>團隊透過回退與修正逐步收斂錯誤。&lt;/li>
&lt;li>事故後回寫 deployment guardrail、decision log 與 evidence 管線。&lt;/li>
&lt;/ol>
&lt;h2 id="可回寫控制面">可回寫控制面&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>控制面&lt;/th>
 &lt;th>暴露缺口&lt;/th>
 &lt;th>回寫方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>變更範圍治理&lt;/td>
 &lt;td>控制面變更可快速全域擴散&lt;/td>
 &lt;td>強制 staged rollout + canary gate&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>決策紀錄&lt;/td>
 &lt;td>假設與回退條件在事中容易遺失&lt;/td>
 &lt;td>強制使用 [8.19] 決策欄位模板&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>證據回寫&lt;/td>
 &lt;td>教訓停留在事件敘事&lt;/td>
 &lt;td>連到 [8.22]，把證據回寫到 observability/reliability 控制面&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>規則推送安全閘門&lt;/td>
 &lt;td>變更工具缺少風險分級&lt;/td>
 &lt;td>回寫 [6.24] 的 rule rollout gate&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>事故決策紀錄： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log&lt;/a>&lt;/li>
&lt;li>事故證據回寫： &lt;a href="https://tarrragon.github.io/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back&lt;/a>&lt;/li>
&lt;li>規則推送安全閘門： &lt;a href="https://tarrragon.github.io/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate&lt;/a>&lt;/li>
&lt;li>觀測治理模型： &lt;a href="https://tarrragon.github.io/blog/backend/04-observability/observability-operating-model/" data-link-title="4.18 Observability Operating Model" data-link-desc="定義 platform / service team / on-call 對訊號、dashboard、alert 與成本的 ownership">4.18 Observability Operating Model&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="引用源">引用源&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.cloudflare.com/cloudflare-incident-on-october-30-2023/">Cloudflare incident on October 30, 2023&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>這起事件的核心責任判讀是：控制面工具設定錯誤會跨越產品邊界擴散，事故第一步要先切斷擴散路徑，再做功能修復。若先把症狀拆成多個產品問題，恢復速度會被 shared dependency 拖慢。</p>
<h2 id="事故摘要">事故摘要</h2>
<p>Cloudflare 在 2023-10-30 發生控制面相關事故，根因涉及 deployment tool 的設定錯誤，影響 Workers KV 與相關服務操作路徑。表面症狀可出現在多個產品面向，但本質是共享控制面變更帶來的連鎖失效。</p>
<p>這類事故和單點 runtime bug 不同。關鍵不是「哪個服務先報錯」，而是「哪個共用控制點先失真」。</p>
<h2 id="判讀訊號">判讀訊號</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>代表意義</th>
          <th>第一波決策價值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>多產品控制操作同時不穩</td>
          <td>shared control dependency 可能失效</td>
          <td>先盤點同批變更與共用工具</td>
      </tr>
      <tr>
          <td>功能異常分布不均</td>
          <td>擴散沿著控制面依賴鏈條走</td>
          <td>用 dependency map 排定恢復優先順序</td>
      </tr>
      <tr>
          <td>回退後錯誤率快速下降</td>
          <td>變更關聯度高</td>
          <td>凍結同類變更、啟動增量復原</td>
      </tr>
      <tr>
          <td>事故中角色交接反覆切換</td>
          <td>ownership 與指揮節奏不足</td>
          <td>固定 single incident commander 與節點交接</td>
      </tr>
  </tbody>
</table>
<h2 id="事故路徑">事故路徑</h2>
<ol>
<li>控制面 deployment tool 變更進入生產。</li>
<li>設定錯誤導致共享控制路徑失真。</li>
<li>Workers KV 與關聯產品出現控制操作異常。</li>
<li>團隊透過回退與修正逐步收斂錯誤。</li>
<li>事故後回寫 deployment guardrail、decision log 與 evidence 管線。</li>
</ol>
<h2 id="可回寫控制面">可回寫控制面</h2>
<table>
  <thead>
      <tr>
          <th>控制面</th>
          <th>暴露缺口</th>
          <th>回寫方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>變更範圍治理</td>
          <td>控制面變更可快速全域擴散</td>
          <td>強制 staged rollout + canary gate</td>
      </tr>
      <tr>
          <td>決策紀錄</td>
          <td>假設與回退條件在事中容易遺失</td>
          <td>強制使用 [8.19] 決策欄位模板</td>
      </tr>
      <tr>
          <td>證據回寫</td>
          <td>教訓停留在事件敘事</td>
          <td>連到 [8.22]，把證據回寫到 observability/reliability 控制面</td>
      </tr>
      <tr>
          <td>規則推送安全閘門</td>
          <td>變更工具缺少風險分級</td>
          <td>回寫 [6.24] 的 rule rollout gate</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>事故決策紀錄： <a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19 Incident Decision Log</a></li>
<li>事故證據回寫： <a href="/blog/backend/08-incident-response/incident-evidence-write-back/" data-link-title="8.22 Incident Evidence Write-back" data-link-desc="把事故證據、決策與復盤結論回寫到 observability、reliability 與 runbook">8.22 Incident Evidence Write-back</a></li>
<li>規則推送安全閘門： <a href="/blog/backend/06-reliability/rule-rollout-safety-gate/" data-link-title="6.24 規則推送安全閘門" data-link-desc="把規則、策略與控制面配置推送從部署步驟升級為可靠性 gate，避免小變更在秒級擴散成全網事故。">6.24 Rule Rollout Safety Gate</a></li>
<li>觀測治理模型： <a href="/blog/backend/04-observability/observability-operating-model/" data-link-title="4.18 Observability Operating Model" data-link-desc="定義 platform / service team / on-call 對訊號、dashboard、alert 與成本的 ownership">4.18 Observability Operating Model</a></li>
</ul>
<h2 id="引用源">引用源</h2>
<ul>
<li><a href="https://blog.cloudflare.com/cloudflare-incident-on-october-30-2023/">Cloudflare incident on October 30, 2023</a></li>
</ul>
]]></content:encoded></item><item><title>Cloudflare Page Shield：用 CSP + SRI + script monitoring 防 client-side supply chain</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/cloudflare-waf/page-shield-csp-sri/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/cloudflare-waf/page-shield-csp-sri/</guid><description>&lt;blockquote>
&lt;p>本文是 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/cloudflare-waf/" data-link-title="Cloudflare WAF" data-link-desc="Edge WAF &amp;#43; DDoS &amp;#43; Bot management 整合套件、global anycast 網路、控制面信任邊界跟客戶側補強的對照">Cloudflare WAF&lt;/a> overview 的 implementation-layer deep article。Overview 已說明 Cloudflare WAF 在入口治理譜系的定位、本文聚焦 &lt;em>Page Shield&lt;/em> 這個 client-side（browser）supply chain attack 防禦工具 — 跟 WAF 攔 server-side request 是不同層。&lt;/p>&lt;/blockquote>
&lt;h2 id="attack-pattern--defense-mechanism-對照">Attack pattern × Defense mechanism 對照&lt;/h2>
&lt;p>Client-side supply chain attack 不會被 WAF 看到 — 攻擊發生在 browser 渲染 page 時、不在 origin server 跟 client 之間的網路層。Page Shield 是 &lt;em>browser-side script execution&lt;/em> 的監測 + 防禦層、跟 WAF 處理 &lt;em>server-side request inspection&lt;/em> 互補不重疊。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Attack pattern&lt;/th>
 &lt;th>表現&lt;/th>
 &lt;th>Page Shield 對應防禦&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Magecart 信用卡 skimmer&lt;/td>
 &lt;td>第三方 JS 被注入惡意 form listener、信用卡資訊送外部 endpoint&lt;/td>
 &lt;td>CSP &lt;code>connect-src&lt;/code> + script alert&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>第三方 SDK 被 compromise&lt;/td>
 &lt;td>廠商 CDN 被攻擊、SDK 改版內含 malicious payload&lt;/td>
 &lt;td>SRI hash mismatch + script alert&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Formjacking&lt;/td>
 &lt;td>結帳頁 form action 被改、submit 送外部 server&lt;/td>
 &lt;td>CSP &lt;code>form-action&lt;/code> directive&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Inline script injection&lt;/td>
 &lt;td>XSS / DOM-based injection 插入 &lt;code>&amp;lt;script&amp;gt;&lt;/code> 跑外部 source&lt;/td>
 &lt;td>CSP &lt;code>script-src&lt;/code> + nonce&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Storage abuse&lt;/td>
 &lt;td>malicious JS 讀 localStorage / cookies 送外部&lt;/td>
 &lt;td>CSP &lt;code>connect-src&lt;/code> + CSP report&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>三層防禦對應不同 attack 階段：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>CSP（Content Security Policy）&lt;/strong>：browser-enforced policy、preventive、阻止違反 policy 的 script load / network request&lt;/li>
&lt;li>&lt;strong>SRI（Subresource Integrity）&lt;/strong>：load 階段 hash 驗證、detective + preventive、廠商 CDN 上 script 被改就 browser 拒載&lt;/li>
&lt;li>&lt;strong>Script monitoring&lt;/strong>：runtime 觀測、detective only、記錄頁面 load 哪些 third-party script、變動時 alert&lt;/li>
&lt;/ol>
&lt;p>三層各有 ceiling — &lt;em>CSP 擋 inline / unauthorized source 但擋不到 allowed source 被 compromise&lt;/em>；&lt;em>SRI 擋已知 vendor 改 hash 但擋不到動態 loader&lt;/em>；&lt;em>monitoring 看得到但攔不到&lt;/em>。Production 三層疊用、不要單一 layer。&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>本文是 <a href="/blog/backend/07-security-data-protection/vendors/cloudflare-waf/" data-link-title="Cloudflare WAF" data-link-desc="Edge WAF &#43; DDoS &#43; Bot management 整合套件、global anycast 網路、控制面信任邊界跟客戶側補強的對照">Cloudflare WAF</a> overview 的 implementation-layer deep article。Overview 已說明 Cloudflare WAF 在入口治理譜系的定位、本文聚焦 <em>Page Shield</em> 這個 client-side（browser）supply chain attack 防禦工具 — 跟 WAF 攔 server-side request 是不同層。</p></blockquote>
<h2 id="attack-pattern--defense-mechanism-對照">Attack pattern × Defense mechanism 對照</h2>
<p>Client-side supply chain attack 不會被 WAF 看到 — 攻擊發生在 browser 渲染 page 時、不在 origin server 跟 client 之間的網路層。Page Shield 是 <em>browser-side script execution</em> 的監測 + 防禦層、跟 WAF 處理 <em>server-side request inspection</em> 互補不重疊。</p>
<table>
  <thead>
      <tr>
          <th>Attack pattern</th>
          <th>表現</th>
          <th>Page Shield 對應防禦</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Magecart 信用卡 skimmer</td>
          <td>第三方 JS 被注入惡意 form listener、信用卡資訊送外部 endpoint</td>
          <td>CSP <code>connect-src</code> + script alert</td>
      </tr>
      <tr>
          <td>第三方 SDK 被 compromise</td>
          <td>廠商 CDN 被攻擊、SDK 改版內含 malicious payload</td>
          <td>SRI hash mismatch + script alert</td>
      </tr>
      <tr>
          <td>Formjacking</td>
          <td>結帳頁 form action 被改、submit 送外部 server</td>
          <td>CSP <code>form-action</code> directive</td>
      </tr>
      <tr>
          <td>Inline script injection</td>
          <td>XSS / DOM-based injection 插入 <code>&lt;script&gt;</code> 跑外部 source</td>
          <td>CSP <code>script-src</code> + nonce</td>
      </tr>
      <tr>
          <td>Storage abuse</td>
          <td>malicious JS 讀 localStorage / cookies 送外部</td>
          <td>CSP <code>connect-src</code> + CSP report</td>
      </tr>
  </tbody>
</table>
<p>三層防禦對應不同 attack 階段：</p>
<ol>
<li><strong>CSP（Content Security Policy）</strong>：browser-enforced policy、preventive、阻止違反 policy 的 script load / network request</li>
<li><strong>SRI（Subresource Integrity）</strong>：load 階段 hash 驗證、detective + preventive、廠商 CDN 上 script 被改就 browser 拒載</li>
<li><strong>Script monitoring</strong>：runtime 觀測、detective only、記錄頁面 load 哪些 third-party script、變動時 alert</li>
</ol>
<p>三層各有 ceiling — <em>CSP 擋 inline / unauthorized source 但擋不到 allowed source 被 compromise</em>；<em>SRI 擋已知 vendor 改 hash 但擋不到動態 loader</em>；<em>monitoring 看得到但攔不到</em>。Production 三層疊用、不要單一 layer。</p>
<h2 id="csp-配置-step-by-step">CSP 配置 step-by-step</h2>
<h3 id="從-cloudflare-dashboard-啟用--寫-policy">從 Cloudflare dashboard 啟用 + 寫 policy</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl"># Dashboard: Security → Page Shield → CSP
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"># 模式: Report-only（第一週）→ Enforced（驗證後）
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"># 範例 policy
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">default-src &#39;self&#39;;
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">script-src &#39;self&#39; &#39;nonce-{NONCE}&#39; https://cdn.trusted.com https://www.googletagmanager.com;
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">style-src &#39;self&#39; &#39;unsafe-inline&#39; https://fonts.googleapis.com;
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">img-src &#39;self&#39; data: https:;
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">connect-src &#39;self&#39; https://api.myapp.com https://*.sentry.io;
</span></span><span class="line"><span class="ln">10</span><span class="cl">form-action &#39;self&#39;;
</span></span><span class="line"><span class="ln">11</span><span class="cl">frame-ancestors &#39;none&#39;;
</span></span><span class="line"><span class="ln">12</span><span class="cl">report-uri https://csp-report.cloudflare.com/cdn-cgi/script_monitor/report;
</span></span><span class="line"><span class="ln">13</span><span class="cl">report-to default;</span></span></code></pre></div><p>關鍵直覺：</p>
<ul>
<li><strong><code>'nonce-{NONCE}'</code></strong>：origin server 每 request 生成 random nonce、注入 <code>&lt;script nonce=&quot;...&quot;&gt;</code> 跟 CSP header；script tag 沒對應 nonce 就被 browser 拒跑、擋 XSS</li>
<li><strong><code>connect-src</code> 精準寫</strong>：第三方 API endpoint 全列出；不寫 <code>*</code> 或 <code>https:</code> 是擋 exfiltration 的關鍵（Magecart 把信用卡送外部 endpoint 就是用 <code>connect-src</code> 攔）</li>
<li><strong><code>form-action</code></strong>：擋 form 被改 action attribute 送外部、formjacking 第一道防線</li>
<li><strong><code>report-uri</code> + <code>report-to</code></strong>：违反 policy 的 event 送 Cloudflare、Page Shield dashboard 看 violation report</li>
</ul>
<h3 id="report-only-mode-第一週">Report-only mode 第一週</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">Content-Security-Policy-Report-Only: &lt;policy&gt;
</span></span><span class="line"><span class="ln">2</span><span class="cl">Content-Security-Policy:             default-src &#39;self&#39;;   # 鬆 policy 仍 enforce</span></span></code></pre></div><p>Report-only 期間 browser <em>report 違反但不擋</em>、production traffic 不受影響；SOC 看 report 找：</p>
<ul>
<li>漏列的 legitimate third-party（marketing / analytics SDK 沒寫進 policy）</li>
<li>意外 inline script（dev 留下的 debug snippet）</li>
<li>跨 domain 的合法 connect（CRM / chat widget）</li>
</ul>
<p>第一週後 dashboard 看 violation 數量趨穩 + 主要違規都已 whitelist、切 Enforced。</p>
<h3 id="enforced-mode-切換--canary">Enforced mode 切換 + canary</h3>
<p>不要直接全站 enforced — 用 Cloudflare Page Rule 對 10% traffic enforced、90% report-only：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">URL pattern: example.com/*
</span></span><span class="line"><span class="ln">2</span><span class="cl">Page Rule: Add CSP header (enforced)
</span></span><span class="line"><span class="ln">3</span><span class="cl">Bypass: 90% by Cookie / IP hash</span></span></code></pre></div><p>10% traffic 跑 24-48h、確認 zero legitimate violation、再擴大到 50% → 100%。canary 期間 monitor <code>error-rate</code> metric、不只是 violation report。</p>
<h2 id="sri-配置">SRI 配置</h2>
<p>Subresource Integrity 用 hash 驗證 CDN-hosted script 沒被改：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://cdn.example.com/widget.v1.2.3.js&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">        <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div><p>Browser load 時算 hash、跟 <code>integrity</code> 不符就拒跑。關鍵：</p>
<ul>
<li><strong>Hash 一定要 version-pinned</strong>：用 <code>widget.v1.2.3.js</code>、不能用 <code>widget.latest.js</code>；廠商更新 latest 時 hash 變 → SRI 拒載 → 服務中斷</li>
<li><strong>多 hash</strong>：寫 <code>integrity=&quot;sha384-... sha512-...&quot;</code> 至少一個 match 就過、可在 vendor rotate hash 時平滑遷移</li>
<li><strong><code>crossorigin=&quot;anonymous&quot;</code></strong> 必加：跨 origin script 預設 browser 不暴露 hash 失敗細節、<code>anonymous</code> 才允許 CORS-based hash check</li>
</ul>
<h3 id="page-shield-自動產-sri-提示">Page Shield 自動產 SRI 提示</h3>
<p>Dashboard → Page Shield → Scripts 列出所有偵測到的 script、含 <em>建議 SRI hash</em>；可以 export 整合進 build pipeline、自動把所有 vendor script 加 SRI。</p>
<h2 id="故障演練">故障演練</h2>
<h3 id="case-1csp-report-floodsoc-noise">Case 1：CSP report flood，SOC noise</h3>
<p><strong>徵兆</strong>：切 Enforced 後、CSP violation report 從每天 ~500 漲到每分鐘 ~50K、Page Shield dashboard 變紅、SOC 收 alert 收到 silent。</p>
<p><strong>根因</strong>：browser extension（廣告攔截 / spell checker / password manager）注入 inline script 跟 connect、被 CSP block 同時觸發 report；不是真實 attack、是 user 端 extension 行為。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>CSP <code>report-sample</code> directive 限 sampling（只 report 10%）— spec 部分支援、不是所有 browser 都認</li>
<li>Page Shield 規則：filter out extension protocol（<code>chrome-extension://</code>、<code>moz-extension://</code>、<code>safari-extension://</code>）後再 alert</li>
<li>Report endpoint 自管 + aggregation：不直接接 SIEM、先 batch + dedupe、再送 SIEM</li>
<li>接受 report flood 是 normal、focus 監測 <em>unique violation pattern</em> 不是 <em>total volume</em></li>
</ol>
<h3 id="case-2inline-script-漏舊頁面突然壞">Case 2：Inline script 漏，舊頁面突然壞</h3>
<p><strong>徵兆</strong>：切 Enforced 後 X 個舊頁面壞、user feedback 提交 form 失敗、debugger 看到 console <code>Refused to execute inline script because it violates...</code>。</p>
<p><strong>根因</strong>：legacy page 有 inline <code>&lt;script&gt;</code> 沒 nonce、CSP enforced 後 browser 拒跑；報表/管理後台/舊 admin page 常見。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>Audit 所有 inline <code>&lt;script&gt;</code>、加 nonce attribute（server-side render 時注入）</li>
<li>短期：對舊頁面用 <code>unsafe-inline</code> 寫進 CSP（接受降級）、page-specific CSP override</li>
<li>長期：legacy page 改 build-time bundle、消除 inline script</li>
</ol>
<h3 id="case-3dynamic-script-loader-繞過-sri">Case 3：Dynamic script loader 繞過 SRI</h3>
<p><strong>徵兆</strong>：vendor script load 成功、但 Page Shield monitoring 看到該 vendor script <em>load 後又動態 load 多個額外 script</em>；額外 script 沒 SRI 保護、廠商側 compromise 直接過。</p>
<p><strong>根因</strong>：第三方 SDK 用 <code>document.createElement('script')</code> + <code>script.src = '...'</code> runtime 動態 load；CSP <code>script-src</code> 可能允許這個來源、但 SRI 沒法在 runtime 注入。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>CSP <code>script-src</code> 精準到 <em>只允許特定 path</em>、不是整個 domain（例：<code>https://cdn.vendor.com/sdk/v3/</code> 而不是 <code>https://cdn.vendor.com</code>）</li>
<li>評估 vendor 是否有 <em>static-only</em> 替代（多數 marketing / analytics SDK 不需要 dynamic loader、是 legacy 設計）</li>
<li>不能消除 dynamic loader 時、Page Shield monitoring 設 <em>new script alert</em>、廠商加 sub-script 即刻通知</li>
</ol>
<h3 id="case-4sri-hash-mismatchvendor-偷偷更新">Case 4：SRI hash mismatch，vendor 偷偷更新</h3>
<p><strong>徵兆</strong>：第三方 widget 突然不顯示、Page Shield 顯示 SRI mismatch、廠商 status page 沒事故公告。</p>
<p><strong>根因</strong>：廠商在 same URL（不是 versioned）下偷偷 push minor patch、hash 變了 → SRI 拒載；不是 attack、是 vendor 不遵守 immutable URL 慣例。</p>
<p><strong>修法</strong>：</p>
<ol>
<li>強制要求廠商提供 versioned URL（<code>widget.v1.2.3.js</code>）、不收 <code>widget.latest.js</code></li>
<li>廠商不配合時、build pipeline 加 <em>daily hash check</em>、廠商偷改 SRI hash 自動更新 + Slack alert</li>
<li>評估換 vendor — 不遵守 immutable URL 的廠商 supply chain integrity 信用低</li>
</ol>
<h2 id="容量--cost">容量 + cost</h2>
<p>Page Shield 是 <em>Enterprise plan + Page Shield add-on</em>、cost 維度：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>影響</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CSP report 量</td>
          <td>Cloudflare 端聚合、不另外計費；report endpoint 自管要 sizing</td>
      </tr>
      <tr>
          <td>Script monitoring</td>
          <td>不影響 page load latency（async detection）</td>
      </tr>
      <tr>
          <td>Per-zone pricing</td>
          <td>跨子域 + apex domain 多 zone 各算一份</td>
      </tr>
      <tr>
          <td>SOC operation</td>
          <td>第一週 report 量大、需要 1-2 analyst FTE 跑 tuning；穩定後低人力</td>
      </tr>
  </tbody>
</table>
<p>Page load 影響：</p>
<ul>
<li>CSP header ~1-2KB（policy 寫越精準越長、不是越短越好）</li>
<li>SRI 比對 ~5-10ms / script、現代 browser cache decoded hash、不重複算</li>
<li>Script monitoring beacon ~100 byte / script load、async 不阻塞 page render</li>
</ul>
<p>實務 default：</p>
<ul>
<li>Critical e-commerce / fintech：CSP enforced + SRI 全 vendor + monitoring all、SOC review weekly</li>
<li>一般 SaaS：CSP report-only ongoing + SRI critical vendor only + monitoring 主域</li>
<li>Marketing / blog：CSP <code>default-src 'self'</code> minimum + monitoring only</li>
</ul>
<h2 id="整合--下一步">整合 / 下一步</h2>
<h3 id="跟-dev-workflow-整合">跟 dev workflow 整合</h3>
<p>CSP 寫進 <em>deploy pipeline</em>、不是 dashboard 手動配：</p>
<ol>
<li>Repo 內 <code>csp-policy.yml</code>、跟 code 同 lifecycle</li>
<li>CI 跑 <em>CSP linter</em>（如 <code>csp-evaluator</code>）、檢查 policy 弱點</li>
<li>Deploy 時 push 到 Cloudflare API、自動 versioning + rollback</li>
</ol>
<h3 id="跟-waf-互補">跟 WAF 互補</h3>
<p>Page Shield 跟 <a href="/blog/backend/07-security-data-protection/vendors/cloudflare-waf/" data-link-title="Cloudflare WAF" data-link-desc="Edge WAF &#43; DDoS &#43; Bot management 整合套件、global anycast 網路、控制面信任邊界跟客戶側補強的對照">Cloudflare WAF</a> 不重疊但互補：</p>
<ul>
<li>WAF 攔 <em>server-side</em> request injection（SQL / command / path traversal）</li>
<li>Page Shield 攔 <em>client-side</em> script execution（XSS / supply chain）</li>
<li>共同 dashboard + alert routing、不要分開 SOC team 看</li>
</ul>
<h3 id="跟-supply-chain-sbom">跟 supply chain SBOM</h3>
<p>Page Shield 偵測的 <em>client-side dependency</em> 可進 SBOM、跟 <a href="/blog/backend/07-security-data-protection/vendors/snyk/" data-link-title="Snyk" data-link-desc="跨 SCM 多模組 application security platform：Open Source (SCA) &#43; Code (SAST) &#43; Container &#43; IaC &#43; Cloud (CSPM)、Reachability analysis">Snyk</a> / <a href="/blog/backend/07-security-data-protection/vendors/dependabot/" data-link-title="Dependabot" data-link-desc="GitHub 原生依賴更新自動化、Version Update &#43; Security Update &#43; Alerts、Grouped Updates 減 PR noise、Auto-merge 配 branch protection">Dependabot</a> 的 server-side SBOM 合併、得到完整 dependency graph。</p>
<h3 id="下一步議題">下一步議題</h3>
<ul>
<li><strong>Trusted Types</strong>：browser-side template injection 的下一代防禦、Chrome 已支援、Firefox / Safari 進度不一</li>
<li><strong>CSP Level 3 + strict-dynamic</strong>：減少 maintenance burden、用 nonce 動態信任 nested script</li>
<li><strong>Reporting API v1</strong>：standard report endpoint + <code>Reporting-Endpoints</code> header 取代 <code>report-uri</code></li>
</ul>
<h2 id="相關連結">相關連結</h2>
<ul>
<li>上游 vendor 頁：<a href="/blog/backend/07-security-data-protection/vendors/cloudflare-waf/" data-link-title="Cloudflare WAF" data-link-desc="Edge WAF &#43; DDoS &#43; Bot management 整合套件、global anycast 網路、控制面信任邊界跟客戶側補強的對照">Cloudflare WAF</a></li>
<li>上游 chapter：<a href="/blog/backend/07-security-data-protection/entrypoint-and-server-protection/" data-link-title="7.3 入口治理與伺服器防護" data-link-desc="以問題驅動方式整理對外入口、管理平面與伺服器邊界">7.3 入口治理與伺服器防護</a>、<a href="/blog/backend/07-security-data-protection/supply-chain-integrity-and-artifact-trust/" data-link-title="7.12 供應鏈完整性與 Artifact 信任" data-link-desc="定義 build provenance、artifact 信任與交付鏈風險問題">7.12 供應鏈完整性</a></li>
<li>對照案例：British Airways 2018 Magecart / Macy&rsquo;s 2019 skimmer（公開 supply chain 案例）</li>
<li>平行 vendor：<a href="/blog/backend/07-security-data-protection/vendors/aws-waf/" data-link-title="AWS WAF" data-link-desc="AWS-internal WAF、跟 ALB / CloudFront / API Gateway 直接整合、Web ACL &#43; Managed Rule Group &#43; Rate-based Rule、Shield Standard 內含">AWS WAF</a> / <a href="/blog/backend/07-security-data-protection/vendors/fastly-ngwaf/" data-link-title="Fastly Next-Gen WAF" data-link-desc="Behavioral / 語意分析 WAF（前 Signal Sciences）、低 false positive、Edge / Agent / Cloud 三種部署模型、API &#43; ATO &#43; Bot 一體">Fastly Next-Gen WAF</a></li>
<li>平行 deep article：<a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/dynamic-credential/" data-link-title="HashiCorp Vault Dynamic Credential：lease 治理跟 application 整合的實作層" data-link-desc="Vault database secrets engine 怎麼配、application 怎麼 renew lease、production 五大踩雷（lease 過期 race、DB max_connections 撞牆、Vault sealed、token expire、scope 過寬）、容量規劃跟 vault-agent injector 整合">Vault Dynamic Credential</a> / <a href="/blog/backend/07-security-data-protection/vendors/splunk/risk-based-alerting/" data-link-title="Splunk Risk-Based Alerting：從 alert per rule 到 score-aggregated notable" data-link-desc="Splunk Enterprise Security 的 RBA 方法論：risk score / modifier / notable 三層 model、ES 配置 step-by-step、tuning playbook（false positive / score inflation / threshold drift / decay）、capacity 成本、跟 SOAR &#43; case management 整合">Splunk RBA</a></li>
<li>Methodology：<a href="/blog/posts/vendor-%E6%B7%B1%E5%BA%A6%E6%8A%80%E8%A1%93%E6%96%87%E7%AB%A0%E6%96%B9%E6%B3%95%E8%AB%96%E7%9A%84%E6%BC%94%E5%8C%96%E7%B4%80%E9%8C%84%E5%90%8C-vendor-%E7%B3%BB%E5%88%97%E7%9A%84%E9%96%8B%E5%A0%B4%E8%BC%AA%E6%9B%BF%E9%A9%97%E8%AD%89/" data-link-title="Vendor 深度技術文章方法論的演化紀錄：同 vendor 系列的開場輪替驗證" data-link-desc="vendor overview 飽和後要寫單一功能深度文章、需要選題與結構依據時回來。這套方法論的驗證來源與 cadence variant 在高風險場景（同 vendor sub-tool 系列）的實證。">Vendor 深度技術文章的寫作方法論</a></li>
</ul>
]]></content:encoded></item><item><title>7.C11 選型：單人遠端 Shell — Tailscale vs Cloudflare Tunnel</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/cases/remote-shell-access-tailscale-vs-cloudflare-tunnel/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/cases/remote-shell-access-tailscale-vs-cloudflare-tunnel/</guid><description>&lt;p>本案例屬於 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/entrypoint-and-server-protection/" data-link-title="7.3 入口治理與伺服器防護" data-link-desc="以問題驅動方式整理對外入口、管理平面與伺服器邊界">7.3 入口治理與伺服器防護&lt;/a> 的選型比較。&lt;/p>
&lt;p>選型情境是&lt;strong>單人自用遠端 shell 存取&lt;/strong>：人在外、手機操作家中或辦公室本機的真實終端機（zsh）。兩個候選方案代表兩種根本不同的安全模型——「公開端點 + 多層防護」vs「私有網路 + 端點不存在」。&lt;/p>
&lt;h2 id="情境約束">情境約束&lt;/h2>
&lt;ul>
&lt;li>單人自用（owner = 開發 = 維運 = 唯一用戶）&lt;/li>
&lt;li>失敗代價高：整台機器的 shell 外洩&lt;/li>
&lt;li>手機端需自建 Flutter 終端機 UI（兩方案皆需）&lt;/li>
&lt;li>預算趨近零（免費方案）&lt;/li>
&lt;/ul>
&lt;h2 id="兩方案架構對比">兩方案架構對比&lt;/h2>
&lt;h3 id="方案-acloudflare-tunnel--cloudflare-access">方案 A：Cloudflare Tunnel + Cloudflare Access&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">Flutter app（Face ID）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> │ WSS，帶三組憑證
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">Cloudflare Tunnel（named，固定網域）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">Cloudflare Access（邊緣：驗 Service Token）── 未授權流量在此被擋
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">Go proxy（本機：驗 X-App-Tunnel-Token）── 第二道
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">ttyd（本機：basic auth）── 第三道
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">zsh&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="方案-btailscale-mesh-vpn">方案 B：Tailscale mesh VPN&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">Flutter app（Face ID）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> │ WS，帶 ttyd basic auth
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">Tailscale mesh VPN（WireGuard 加密隧道，裝置級認證）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">Go proxy（本機：稽核 log + 透明轉發，不做認證）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">ttyd（本機：basic auth）── 應用層最後防線
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> ▼
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">zsh&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="核心選型維度">核心選型維度&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>Cloudflare Tunnel + Access&lt;/th>
 &lt;th>Tailscale&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>網路模型&lt;/strong>&lt;/td>
 &lt;td>出站連線到 CF 邊緣，產生&lt;strong>公開 URL&lt;/strong>&lt;/td>
 &lt;td>&lt;a href="https://www.wireguard.com/">WireGuard&lt;/a> mesh VPN，裝置間&lt;strong>私有 IP&lt;/strong>，無公開端點&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>攻擊面&lt;/strong>&lt;/td>
 &lt;td>公開 URL 存在，需層層防護&lt;/td>
 &lt;td>服務端點不存在於公開網路，攻擊者連 IP 都到不了&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>認證層數&lt;/strong>&lt;/td>
 &lt;td>三層：CF Access + proxy token + ttyd&lt;/td>
 &lt;td>兩層：Tailscale 裝置認證 + ttyd&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Go proxy 職責&lt;/strong>&lt;/td>
 &lt;td>驗 token + 稽核 log + 轉發&lt;/td>
 &lt;td>稽核 log + 轉發（不做認證）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>元件數&lt;/strong>&lt;/td>
 &lt;td>5（app → CF → CF Access → proxy → ttyd）&lt;/td>
 &lt;td>3（app → Tailscale → proxy/ttyd）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>需要自有網域&lt;/strong>&lt;/td>
 &lt;td>是&lt;/td>
 &lt;td>否（MagicDNS 自動分配）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>啟停行程數&lt;/strong>&lt;/td>
 &lt;td>3（cloudflared + ttyd + proxy）&lt;/td>
 &lt;td>2（ttyd + proxy），Tailscale daemon 常駐&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>憑證包欄位&lt;/strong>&lt;/td>
 &lt;td>8 欄（含 CF Access 憑證 + proxy token）&lt;/td>
 &lt;td>~5 欄（endpoint + ttyd 帳密）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>密鑰管理複雜度&lt;/strong>&lt;/td>
 &lt;td>高（proxy token 需可插拔後端 keychain/file/env）&lt;/td>
 &lt;td>低（僅 ttyd 帳密）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>費用&lt;/strong>&lt;/td>
 &lt;td>免費（Cloudflare 個人方案）&lt;/td>
 &lt;td>免費（Tailscale 個人方案，100 裝置內）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>外部依賴&lt;/strong>&lt;/td>
 &lt;td>Cloudflare 邊緣網路 + CF Access 控制面&lt;/td>
 &lt;td>Tailscale 協調伺服器 + DERP relay&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>供應商不可用時降級&lt;/strong>&lt;/td>
 &lt;td>邊緣不可用 = 全部連不進來；已建立連線可能存活&lt;/td>
 &lt;td>協調伺服器不可用時已建立的 WireGuard 連線存活；DERP relay 不可用只影響 NAT 穿越&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="選型判讀">選型判讀&lt;/h2>
&lt;h3 id="tailscale-勝出的場景本情境適用">Tailscale 勝出的場景（本情境適用）&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>攻擊面最小化是首要目標&lt;/strong>：shell 閘道的失敗代價極高，「端點不存在」比「保護公開端點」本質上更安全&lt;/li>
&lt;li>&lt;strong>單人自用&lt;/strong>：不需要 CF Access 的多人 policy / IdP 整合 / Device Posture 等企業功能&lt;/li>
&lt;li>&lt;strong>架構簡單性&lt;/strong>：從 5 元件 3 層認證縮為 3 元件 2 層認證，Go proxy 職責大幅簡化（砍認證閘道，只留 log + 轉發）&lt;/li>
&lt;li>&lt;strong>密鑰管理簡化&lt;/strong>：不再需要為 proxy token 建可插拔多後端（keychain/file/env），只管 ttyd 帳密&lt;/li>
&lt;li>&lt;strong>不需要自有網域&lt;/strong>：Tailscale MagicDNS 或直接用 Tailscale IP&lt;/li>
&lt;/ul>
&lt;h3 id="cloudflare-tunnel-勝出的場景本情境不適用但值得記錄">Cloudflare Tunnel 勝出的場景（本情境不適用，但值得記錄）&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>需要對外提供服務&lt;/strong>（非自用）：CF 的 WAF / CDN / rate limit / bot protection 生態豐富&lt;/li>
&lt;li>&lt;strong>需要 HTTP 層細粒度存取控制&lt;/strong>：CF Access 的 Application + Policy 模型適合管多個 internal web app&lt;/li>
&lt;li>&lt;strong>需要 Device Posture 檢查&lt;/strong>：CF 整合 CrowdStrike / SentinelOne 等 EDR 做裝置健康判斷（Device Posture：在授權前先檢查裝置的安全狀態 — 作業系統版本、磁碟加密、防毒軟體是否啟用）&lt;/li>
&lt;li>&lt;strong>已在用 Cloudflare 生態&lt;/strong>：共用控制面的管理紅利（同一 Logpush / API token / Audit Log）&lt;/li>
&lt;li>&lt;strong>多人 / 多團隊 / 合規場景&lt;/strong>：CF Access 的 IdP 整合 + Service Auth + Audit Log 比 Tailscale 個人方案完整&lt;/li>
&lt;/ul>
&lt;h3 id="邊界情境">邊界情境&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>多人但仍小規模&lt;/strong>（2-5 人）：Tailscale ACL（存取控制清單，定義哪些裝置可存取哪些服務）足以控制；超過此規模再評估 CF Access 或 Teleport&lt;/li>
&lt;li>&lt;strong>需要 session recording&lt;/strong>：兩者都沒有一流方案——Tailscale 需 Enterprise tier，CF Access 只記 metadata 不錄 keystroke。重 audit 走 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &amp;#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &amp;#43; session recording &amp;#43; JIT、跟 Okta / Vault 互補">Teleport&lt;/a>&lt;/li>
&lt;li>&lt;strong>需要從固定 IP 出網&lt;/strong>：Tailscale Exit Node 可做但不是設計核心；CF 有更成熟的方案&lt;/li>
&lt;/ul>
&lt;h2 id="tailscale-採用後的安全底線">Tailscale 採用後的安全底線&lt;/h2>
&lt;p>即使 Tailscale 攻擊面更小，仍需維持以下底線：&lt;/p></description><content:encoded><![CDATA[<p>本案例屬於 <a href="/blog/backend/07-security-data-protection/entrypoint-and-server-protection/" data-link-title="7.3 入口治理與伺服器防護" data-link-desc="以問題驅動方式整理對外入口、管理平面與伺服器邊界">7.3 入口治理與伺服器防護</a> 的選型比較。</p>
<p>選型情境是<strong>單人自用遠端 shell 存取</strong>：人在外、手機操作家中或辦公室本機的真實終端機（zsh）。兩個候選方案代表兩種根本不同的安全模型——「公開端點 + 多層防護」vs「私有網路 + 端點不存在」。</p>
<h2 id="情境約束">情境約束</h2>
<ul>
<li>單人自用（owner = 開發 = 維運 = 唯一用戶）</li>
<li>失敗代價高：整台機器的 shell 外洩</li>
<li>手機端需自建 Flutter 終端機 UI（兩方案皆需）</li>
<li>預算趨近零（免費方案）</li>
</ul>
<h2 id="兩方案架構對比">兩方案架構對比</h2>
<h3 id="方案-acloudflare-tunnel--cloudflare-access">方案 A：Cloudflare Tunnel + Cloudflare Access</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Flutter app（Face ID）
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">   │  WSS，帶三組憑證
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Cloudflare Tunnel（named，固定網域）
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Cloudflare Access（邊緣：驗 Service Token）── 未授權流量在此被擋
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Go proxy（本機：驗 X-App-Tunnel-Token）── 第二道
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln">10</span><span class="cl">ttyd（本機：basic auth）── 第三道
</span></span><span class="line"><span class="ln">11</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln">12</span><span class="cl">zsh</span></span></code></pre></div><h3 id="方案-btailscale-mesh-vpn">方案 B：Tailscale mesh VPN</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">Flutter app（Face ID）
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">   │  WS，帶 ttyd basic auth
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Tailscale mesh VPN（WireGuard 加密隧道，裝置級認證）
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Go proxy（本機：稽核 log + 透明轉發，不做認證）
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">ttyd（本機：basic auth）── 應用層最後防線
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   ▼
</span></span><span class="line"><span class="ln">10</span><span class="cl">zsh</span></span></code></pre></div><h2 id="核心選型維度">核心選型維度</h2>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>Cloudflare Tunnel + Access</th>
          <th>Tailscale</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>網路模型</strong></td>
          <td>出站連線到 CF 邊緣，產生<strong>公開 URL</strong></td>
          <td><a href="https://www.wireguard.com/">WireGuard</a> mesh VPN，裝置間<strong>私有 IP</strong>，無公開端點</td>
      </tr>
      <tr>
          <td><strong>攻擊面</strong></td>
          <td>公開 URL 存在，需層層防護</td>
          <td>服務端點不存在於公開網路，攻擊者連 IP 都到不了</td>
      </tr>
      <tr>
          <td><strong>認證層數</strong></td>
          <td>三層：CF Access + proxy token + ttyd</td>
          <td>兩層：Tailscale 裝置認證 + ttyd</td>
      </tr>
      <tr>
          <td><strong>Go proxy 職責</strong></td>
          <td>驗 token + 稽核 log + 轉發</td>
          <td>稽核 log + 轉發（不做認證）</td>
      </tr>
      <tr>
          <td><strong>元件數</strong></td>
          <td>5（app → CF → CF Access → proxy → ttyd）</td>
          <td>3（app → Tailscale → proxy/ttyd）</td>
      </tr>
      <tr>
          <td><strong>需要自有網域</strong></td>
          <td>是</td>
          <td>否（MagicDNS 自動分配）</td>
      </tr>
      <tr>
          <td><strong>啟停行程數</strong></td>
          <td>3（cloudflared + ttyd + proxy）</td>
          <td>2（ttyd + proxy），Tailscale daemon 常駐</td>
      </tr>
      <tr>
          <td><strong>憑證包欄位</strong></td>
          <td>8 欄（含 CF Access 憑證 + proxy token）</td>
          <td>~5 欄（endpoint + ttyd 帳密）</td>
      </tr>
      <tr>
          <td><strong>密鑰管理複雜度</strong></td>
          <td>高（proxy token 需可插拔後端 keychain/file/env）</td>
          <td>低（僅 ttyd 帳密）</td>
      </tr>
      <tr>
          <td><strong>費用</strong></td>
          <td>免費（Cloudflare 個人方案）</td>
          <td>免費（Tailscale 個人方案，100 裝置內）</td>
      </tr>
      <tr>
          <td><strong>外部依賴</strong></td>
          <td>Cloudflare 邊緣網路 + CF Access 控制面</td>
          <td>Tailscale 協調伺服器 + DERP relay</td>
      </tr>
      <tr>
          <td><strong>供應商不可用時降級</strong></td>
          <td>邊緣不可用 = 全部連不進來；已建立連線可能存活</td>
          <td>協調伺服器不可用時已建立的 WireGuard 連線存活；DERP relay 不可用只影響 NAT 穿越</td>
      </tr>
  </tbody>
</table>
<h2 id="選型判讀">選型判讀</h2>
<h3 id="tailscale-勝出的場景本情境適用">Tailscale 勝出的場景（本情境適用）</h3>
<ul>
<li><strong>攻擊面最小化是首要目標</strong>：shell 閘道的失敗代價極高，「端點不存在」比「保護公開端點」本質上更安全</li>
<li><strong>單人自用</strong>：不需要 CF Access 的多人 policy / IdP 整合 / Device Posture 等企業功能</li>
<li><strong>架構簡單性</strong>：從 5 元件 3 層認證縮為 3 元件 2 層認證，Go proxy 職責大幅簡化（砍認證閘道，只留 log + 轉發）</li>
<li><strong>密鑰管理簡化</strong>：不再需要為 proxy token 建可插拔多後端（keychain/file/env），只管 ttyd 帳密</li>
<li><strong>不需要自有網域</strong>：Tailscale MagicDNS 或直接用 Tailscale IP</li>
</ul>
<h3 id="cloudflare-tunnel-勝出的場景本情境不適用但值得記錄">Cloudflare Tunnel 勝出的場景（本情境不適用，但值得記錄）</h3>
<ul>
<li><strong>需要對外提供服務</strong>（非自用）：CF 的 WAF / CDN / rate limit / bot protection 生態豐富</li>
<li><strong>需要 HTTP 層細粒度存取控制</strong>：CF Access 的 Application + Policy 模型適合管多個 internal web app</li>
<li><strong>需要 Device Posture 檢查</strong>：CF 整合 CrowdStrike / SentinelOne 等 EDR 做裝置健康判斷（Device Posture：在授權前先檢查裝置的安全狀態 — 作業系統版本、磁碟加密、防毒軟體是否啟用）</li>
<li><strong>已在用 Cloudflare 生態</strong>：共用控制面的管理紅利（同一 Logpush / API token / Audit Log）</li>
<li><strong>多人 / 多團隊 / 合規場景</strong>：CF Access 的 IdP 整合 + Service Auth + Audit Log 比 Tailscale 個人方案完整</li>
</ul>
<h3 id="邊界情境">邊界情境</h3>
<ul>
<li><strong>多人但仍小規模</strong>（2-5 人）：Tailscale ACL（存取控制清單，定義哪些裝置可存取哪些服務）足以控制；超過此規模再評估 CF Access 或 Teleport</li>
<li><strong>需要 session recording</strong>：兩者都沒有一流方案——Tailscale 需 Enterprise tier，CF Access 只記 metadata 不錄 keystroke。重 audit 走 <a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a></li>
<li><strong>需要從固定 IP 出網</strong>：Tailscale Exit Node 可做但不是設計核心；CF 有更成熟的方案</li>
</ul>
<h2 id="tailscale-採用後的安全底線">Tailscale 採用後的安全底線</h2>
<p>即使 Tailscale 攻擊面更小，仍需維持以下底線：</p>
<table>
  <thead>
      <tr>
          <th>底線</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>ttyd 綁 Tailscale 介面或 localhost</td>
          <td>不監聽公開網路介面</td>
      </tr>
      <tr>
          <td>Tailscale ACL 限制裝置</td>
          <td>只有 owner 裝置可存取 proxy port</td>
      </tr>
      <tr>
          <td>ttyd basic auth</td>
          <td>Tailscale 萬一被穿越的最後防線</td>
      </tr>
      <tr>
          <td>稽核 log</td>
          <td>proxy 記錄每次連線（client_ip，不含 PTY 內容）</td>
      </tr>
      <tr>
          <td>不開機自啟（ttyd/proxy）</td>
          <td>手動起停最小化服務暴露窗</td>
      </tr>
  </tbody>
</table>
<h2 id="此選型的-tripwire">此選型的 tripwire</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>觸發後重評</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>從單人變多人</td>
          <td>Tailscale ACL 是否足夠，或需升級為 Teleport / CF Access</td>
      </tr>
      <tr>
          <td>需要對外暴露服務</td>
          <td>Tailscale Funnel 不適合 production hardened ingress，改走 CF</td>
      </tr>
      <tr>
          <td>需要合規 session recording</td>
          <td>Tailscale Enterprise 或改走 Teleport</td>
      </tr>
      <tr>
          <td>需要 WAF / bot protection</td>
          <td>Tailscale 沒有應用層防護，改走 CF</td>
      </tr>
      <tr>
          <td>Tailscale key 即將到期</td>
          <td>確認 key expiry 政策（預設 180 天）、設提醒避免裝置靜默掉線</td>
      </tr>
  </tbody>
</table>
<h2 id="從本情境到-vendor-詳頁">從本情境到 vendor 詳頁</h2>
<ul>
<li>Tailscale 完整 vendor 判讀 → <a href="/blog/backend/07-security-data-protection/vendors/tailscale-ssh/" data-link-title="Tailscale SSH" data-link-desc="WireGuard-based zero-trust mesh &#43; identity-bound SSH、ACL JSON policy、developer-friendly、跟 IdP integration 取代 SSH key">Tailscale SSH</a></li>
<li>Cloudflare Access 完整 vendor 判讀 → <a href="/blog/backend/07-security-data-protection/vendors/cloudflare-access/" data-link-title="Cloudflare Access" data-link-desc="Zero Trust Network Access (ZTNA)、取代 VPN 的 application-layer access、Argo Tunnel &#43; Device Posture &#43; IdP integration">Cloudflare Access</a></li>
<li>Infrastructure access + 合規場景 → <a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a></li>
<li>本選型的章節歸屬 → <a href="/blog/backend/07-security-data-protection/entrypoint-and-server-protection/" data-link-title="7.3 入口治理與伺服器防護" data-link-desc="以問題驅動方式整理對外入口、管理平面與伺服器邊界">7.3 入口治理與伺服器防護</a></li>
</ul>
]]></content:encoded></item></channel></rss>