在這個高度依賴 CDN 與邊緣運算的年代,Cloudflare 的一個噴嚏,往往就是全球網際網路的一場重感冒。
就在昨日(2025 年 11 月 18 日),全球數以百萬計的網站一度陷入癱瘓,瀏覽器上熟悉的 5xx 錯誤頁面讓許多維運人員冒冷汗,都快有 PTSD 了。起初,不少人,甚至包括 Cloudflare 自己的工程團隊,都懷疑這是一場超大規模的 DDoS 攻擊。然而,官方稍早釋出的事故剖析報告(Post Mortem)證實了這其實不是駭客攻擊,而是一次資料庫權限變更引發的連鎖掛點事件。
Cloudflare 執行長 Matthew Prince 親自撰文證實,這次導致全球半個網路癱瘓的事故,並非網路攻擊 (DDoS),而是一起典型的「內部變更管理 (Change Management) 災難」。
一個看似無害的資料庫權限調整,導致內部 ClickHouse 查詢回傳了遠超過預期的資料量,使機器人防護(Bot Management)系統生成了一份異常巨大的特徵檔(feature file)。當這份錯誤的檔案被載入核心轉發引擎(core proxy)時,因特徵數量超出程式設計上限而觸發 Rust 的 runtime panic,最終造成全球節點的 HTTP 代理程序接連崩潰。
CyberQ 認為這次事件是分散式系統脆弱性的一個教科書級案例,以下是這次事故的技術細節與關鍵轉折。
本次事件關鍵時間軸 (Timeline)
11:05 UTC (19:05 台灣時間): 部署資料庫權限變更 (災難的種子)。
11:20 UTC (19:20 台灣時間): 變更生效,錯誤的設定檔派發至全球,核心服務開始崩潰 (Impact Starts)。
11:30 – 13:05 UTC: 團隊誤以為是 DDoS 攻擊(因為連自家 Status Page 都剛好掛了),浪費了寶貴的檢查排除錯誤時間。
13:05 UTC (21:05 台灣時間): 團隊手動讓 Access 和 KV 繞過 (Bypass) 核心 Proxy,這就是我們在上一篇報導中看到 Access 率先恢復的轉折點。
14:24 UTC (22:24 台灣時間): 確認元兇是 Bot Management 設定檔,停止派發新檔並 Rollback。
14:30 UTC (22:30 台灣時間): 主流服務開始恢復。
17:06 UTC (01:06 台灣時間): 全球服務完全恢復正常。
從權限變更到記憶體崩潰的蝴蝶效應
整起事件的引爆點,源自於 UTC 時間 11:05 的一個看似無害的操作。Cloudflare 工程團隊為了改善資料庫權限管理,對其 ClickHouse 叢集進行了一次更新。
1、導火線:ClickHouse 的隱式權限
Cloudflare 的機器人管理系統(Bot Management)依賴一個名為「特徵檔(feature file)」的設定檔來判斷流量是否為惡意機器人。這個檔案是透過查詢 ClickHouse 資料庫定期生成的。
原本的查詢語法假設回傳的欄位只會來自 default 資料庫。然而,新的權限變更讓系統帳號能夠「顯式」看到底層 r0 資料庫的表格。 結果是:SQL 查詢在沒有指定資料庫名稱的情況下,回傳了雙倍的欄位資料(包含 default 和 r0 的重複項)。
2、增幅:特徵檔膨脹
這個雙倍的查詢結果,導致產生的「特徵檔」大小瞬間暴增。檔案中的特徵數量超過了系統預期。
3、引爆:Rust 程式碼的 unwrap() panic
Cloudflare 的核心代理服務(Proxy)為了效能最佳化,在記憶體分配上採取了預先分配(preallocation)策略。 bot 機器人管理模組其實有設定了一個上限,特徵數量不得超過 200 個,目前實際則是約使用 60 個。
當這個含有重複資料、超過 200 個特徵的設定檔被推送到全球節點時,執行在 FL2(新版 Proxy 引擎)上的 Rust 程式碼觸發了檢查機制。但沒想到,這個錯誤處理邏輯似乎過於激進,程式碼執行了 Result::unwrap() 在一個錯誤值(Err)上,直接導致執行緒崩潰。
Rust
// 官方報告揭露的崩潰訊息
thread fl2_worker_thread panicked: called Result::unwrap() on an Err value
這一行程式碼的崩潰,讓負責處理核心流量的 Proxy 服務陷入無限重啟與失敗的循環,導致了全球範圍的 5xx 錯誤。
誤判與混亂,為何第一時間以為是 DDoS?
事故發生初期(UTC 11:20),Cloudflare 內部也經歷了一陣混亂。由於系統會不斷嘗試重新讀取設定檔(有時讀到舊的好檔,有時讀到新的壞檔),導致錯誤率呈現劇烈波動。這種「間歇性」的服務中斷,加上近期高強度的 DDoS 攻擊潮,讓團隊誤判形勢。
更巧合的是,Cloudflare 的外部狀態頁面(Status Page)剛好也在這時掛點,雖然事後證實無關,這讓工程師一度以為攻擊者是針對性的同時攻擊基礎設施與通訊管道。
影響範圍與復原
重災區: 核心 CDN 服務、WAF、Turnstile 驗證、Workers KV 以及 Access 登入服務。
復原關鍵: 團隊在 UTC 13:05 先針對 Workers KV 實施繞過(Bypass)策略,隨後鎖定問題在於機器人管理模組的設定檔。
最終解法: 停止自動生成新設定檔,手動 Rollback 到舊版已知良好的版本,並強制重啟核心 Proxy。服務於 UTC 14:30 大致恢復,17:06 全面排除。
資訊系統韌性的再思考
CyberQ觀點,這次 Cloudflare 的事故給所有 IT 與資訊/資安從業人員上了寶貴的一課:
輸入驗證(Input Validation)不能只對外, 我們常強調防禦使用者輸入的惡意資料,但對於「內部系統產生的設定檔」,往往缺乏同樣嚴格的驗證機制。Cloudflare 承諾未來將對內部生成的設定檔實施與使用者輸入同等級的硬化措施。其實呢,要看中輸入驗證這點,因為即使是「內部產生」的設定檔,也必須視為「不可信的輸入」。如果在讀取設定檔時,程式能捕捉到「長度超標」並選擇「忽略新設定,沿用舊設定」,這場全球災難就有可能完全避免。
在 Rust 或任何現代語言中,unwrap() 雖然方便,但在關鍵路徑(Critical Path)上使用它無異於埋設地雷。優雅降級(Graceful Degradation)是一種必要的策略,比方說當設定檔過大時,紀錄錯誤並使用舊版設定,這是我們在部署與規劃高可用性系統設計的思維,畢竟單一模組 Bot Management 的故障不該拖垮 Cloudflare 的整個核心引擎 Core Proxy。未來的架構設計應考慮更強的隔離性 (Sandboxing),讓非關鍵模組崩潰時,核心流量仍能通過(Fail Open)。
可觀測性的雙面刃在報告中也能看得到問題點,這次事故期間 CDN 延遲增加,部分原因是除錯(Debugging)系統為了捕捉錯誤而消耗了大量 CPU。當系統瀕臨崩潰時,過度的診斷機制反而可能成為壓垮駱駝的最後一根稻草。而事故初期,工程師Cloudflare被「Status Page 剛好也掛了」以及「類似 DDoS 的流量特徵」誤導。這提醒我們在緊急應變時,如何快速排除巧合並找出正確的鎮政原因,是縮短 MTTR (平均修復時間) 的關鍵。
Cloudflare 在報告末尾坦承這是自 2019 年以來最嚴重的事故。作為網路基礎設施的守門人,這次被自己絆倒的經驗雖然慘痛,但他們詳盡的技術揭露(Post Mortem)展現了負責任的態度,這在業界仍值得肯定。
對於依賴單一雲服務的企業來說,這也是一次檢視自身災難復原(DR)計畫的機會,當 Cloudflare 倒下時,你的 B 計畫是什麼呢?
本文題圖由 Google Gemini AI 模型生成










