警報疲勞:資安監控程式一天寄出82封電子郵件

一個人的資安監控程式,應該發出多少警報? 依我的數字,大約一天一封電子郵件,再加上偶爾一封真正需要我動手處理的。11月1日,從午夜到太平洋時間13:32,我的監控程式交給郵件服務74封電子郵件:55封是關於它已經執行的封鎖,16封嚴重(critical)警報,兩封每小時流量警報,還有一封來自我 Mac 上的掃描器。12 那天下午我的解讀是:每一封描述的都是 edge 早已擋下的例行掃描;3 就那幾波嚴重等級的洪泛而言,第6節會說明這個解讀太過寬厚。解法是一套政策,而不是一個閾值:每天一封摘要,同時兼任心跳訊號;封鎖改發到聊天頻道而非郵件;edge 已經處理的嚴重警報併入摘要;每一筆雲端嚴重警報都寫上處置結果。隔天,一台掃描器在不到六分鐘內對我的多個網站觸發四筆嚴重警報,而我的監控程式為此寄出的電子郵件是零封。4 那一天仍然產生了19封電子郵件,而不是一封;其中的原因,是整個故事最有用的部分。5

我的監控程式寄出的郵件,讀者只有我一個人。當收件匣顯示74封時,我問的是:這些是例行公事,還是真正的威脅?誠實的答案是,監控程式無法從主旨告訴我,因為每一封的主旨都在說同一件事,只是音量不同。1 一個監控程式,一旦唯一的讀者不再閱讀它,就已經停止監控,無論它的偵測器還抓得到什麼。以下依序是:計數、取而代之的政策、一個測試案例,以及這個故事的乾淨版本在三個地方破功之處。

重點摘要

  • 13:32前74封,午夜前82封。 我自己記的表格和從日誌推導出的計數,在我抱怨之前的數字一致,都是74封(55封逐筆封鎖通知、16封嚴重警報、兩封每小時警報、一封本機警報);11月1日全天則是日誌記錄的81封,加上一封我手動寄出的摘要。125
  • 74封中有22封無法證實。 它們來自一段程式碼:沒有檢查郵件服務的回應就記下「sent」(已寄出),因此日誌只能證明曾嘗試交付,不能證明訊息真的送達。26
  • 文獻早就寫好了規則。 Google 的 SRE 書只允許三種輸出(警報、工單與日誌記錄),寫道「Every page should be actionable」(每一次呼叫都應該是可採取行動的),並把電子郵件警報稱為「alert spam」(警報垃圾郵件);The Joint Commission(美國醫療機構評鑑聯合委員會)的警示引用一項估計:「between 85 and 99 percent of alarm signals do not require clinical intervention」(85%到99%的警報訊號不需要臨床介入)。78910
  • 測試案例成功了。 11月2日,一家荷蘭主機代管業者的一個位址,在5分51秒內對我的網站觸發四筆嚴重警報;監控程式封鎖它一次,把封鎖貼到聊天頻道,將每一筆嚴重警報都併入摘要,沒有寄出任何電子郵件。41112
  • 隔天仍寄出19封,而不是一封。 其中14封是 WAF 洪泛嚴重警報,其中有些事件沒有記錄到封鎖或質詢(challenge),而它們的主旨寫著「WAF blocks」(WAF 封鎖),即使 edge 一個事件都沒有封鎖(當天兩次;前一晚有一封寫著「104 WAF blocks」,而 edge 根本沒有封鎖或質詢任何事件);我第一次改寫主旨,就在完成計數的那天,仍然在同一行裡混用了兩種計數,是這篇文章的審查抓出來的。51314
  • 有兩個訊號是錯的。 我 Mac 上的一項程式碼簽章檢查,把 Apple 自家的 Spotlight 常駐程式判定為未簽署的加密貨幣挖礦程式;摘要中的「RUNS SHORT 162/207」(執行次數不足)則證明一部分是睡眠,一部分是比預期慢的實際執行節奏,還有一部分,從時間點判斷,是看門狗(watchdog)終止的三次執行。151617
  • 改了什麼: 每天一封摘要,承載心跳訊號、每一次封鎖,以及每一筆雲端嚴重警報的處置結果;只有兩種併入條件都不涵蓋的嚴重警報、每小時流量警報,以及本機掃描器,仍會立即寄信。11月1日的82封電子郵件,到了11月2日變成19封。185

1. 11月1日的收件匣

11月1日太平洋時間13:32,我寫信給負責管理我基礎設施的代理程式工作階段:監控程式的電子郵件塞爆了我的收件匣;有沒有什麼該改的?這些是例行公事,還是真正的威脅?1 我那天下午記的表格,依寄件來源統計了午夜以來的74封電子郵件:55封逐筆封鎖通知、16封嚴重警報、兩封每小時流量警報,以及一封來自我 Mac 上掃描器的嚴重警報。1

這個計數建立在一條規則上,所以先交代規則,再談數字。在本文中,一封電子郵件指的是監控程式日誌裡記錄一次交付給郵件服務的一行。一支腳本走過10月31日至11月2日的六個日誌檔,把每一行這類紀錄依串流與處置結果分類。5 截至13:32,腳本與我的表格在每個串流上都一致:55、16、兩封、一封,合計74封。2 整個當地日期到午夜為止,日誌記錄了81封電子郵件(55封逐筆封鎖、22封嚴重、三封每小時、一封本機),再加上一封我在13:48手動寄出的摘要;那封摘要在監控程式的日誌裡沒有寄送紀錄,合計82封。51

這份一致性裡有兩個細節很重要。我的表格對嚴重警報寫的是「9 before the fold went live at 00:30 PT; the 7 after」(併入機制於太平洋時間00:30上線前9封,之後7封);日誌顯示00:30之前有11行嚴重警報的「sent」紀錄,之後有五行,而第一筆併入封鎖通知的嚴重警報出現在00:54:43,晚於併入機制的變更在 PDT 00:46 落地的時刻,而不是我的表格所寫的00:30。218 總數相符;我手寫的分拆差了兩封。第二個細節更大。在74封中,有22封(10封逐筆封鎖、11封嚴重、一封每小時)來自那些把郵件服務的回應直接丟棄、然後不管回傳什麼都記下「sent」的寄件程式。26 當天早上01:04 PDT,在時鐘回撥之前,一項修正讓雲端那一半的寄件程式記錄服務的 HTTP 狀態碼,只有在收到2xx時才寫「sent」;本機掃描器的寄件程式則只寫一行單純的「Critical email sent」(嚴重警報郵件已寄出),而且只在請求沒有拋出錯誤時才寫。6 那22行較早的紀錄證明監控程式嘗試過;它們不能證明郵件服務接受了任何東西。我10月31日的日誌判斷雲端郵件「most likely were」(很可能已經)送達,這是合理的猜測,但仍然只是猜測。19

即使是2xx,證明的也比「sent」這個字暗示的少。Resend 的文件把它的 email.sent 事件定義為「Occurs whenever the API request was successful. Resend will attempt to deliver the message to the recipient’s mail server」(每當 API 請求成功時發生;Resend 會嘗試把訊息遞送到收件人的郵件伺服器),並把遞送列為另一個、較晚的事件。20 寄送呼叫本身回傳的是一個 id。21 下文的每一個計數,都是郵件服務接受的交付次數;至於11月1日的22封和10月31日的10封,共32封,則是監控程式嘗試的交付次數。5 其中沒有任何一個是我讀過的訊息數。

依小時來看,這一天就像一道懸崖接著一片高原。

11月1日依當地小時的長條圖,01:00這個小時因夏令時間結束而出現兩次。藍色長條是寄出的電子郵件:午夜那個小時22封,接著是8、5、5、4、2、4、3、4、4、3、3、3、3,到13:00那個小時為1。13:50的虛線標示「一天一封電子郵件」的變更;之後藍色長條依序為1、0、2、0、1、1、1、0、1與0。灰色長條是改為併入或抑制、而非寄出的警報:變更前每小時1到8筆,變更後每小時3到23筆。

11月1日,當地時間:每小時的電子郵件數,對照沒有變成郵件的警報數,並標出13:50的政策變更。22

第一個小時有22封電子郵件,全部來自未經驗證的程式碼(10封逐筆封鎖、11封嚴重、一封每小時)。22 之後,逐筆封鎖通知以每小時一到五封的速度持續,因為 edge 不斷封鎖掃描器,而每一次封鎖都寫一封信給我。最後一封逐筆封鎖郵件在13:25:57寄出;第一筆改為併入摘要的逐筆封鎖通知出現在14:20:35。22 13:50的變更之後,電子郵件降到每小時零到兩封,而併入與抑制的警報則攀升到每小時多達23筆。22 流量沒有減少。減少的是電子郵件。

前一天是個糟糕的基準。我11月1日的日誌寫著「Yesterday had 10」(昨天有10封),腳本也同意,但10月31日的日誌從22:31才開始,也就是我重新啟用監控程式的那個晚上,所以那10封電子郵件只涵蓋89分鐘。15 依我的解讀,那74封測量的是偵測器在一整天網際網路背景雜訊下的正常運作,而不是掃描器的行為有了什麼改變。

2. 這些警報原本的用途

監控程式分成兩半。雲端那一半排程在我的 Mac 上每五分鐘執行一次,向 Cloudflare 查詢我每個區域(zone)的防火牆事件與分組請求計數:哪些位址打了哪些路徑、多頻繁,以及 edge 對每個事件採取了什麼動作。1823 Cloudflare 自己對這些資料的描述,正是看待它的正確框架:「Security Events displays information about requests actioned or flagged by Cloudflare security products, including features such as Browser Integrity Check.」(Security Events 顯示被 Cloudflare 安全產品處置或標記的請求資訊,包括 Browser Integrity Check 等功能。)24 本機那一半是一台掃描器,每10分鐘分層檢查 Mac 本身:行程及其程式碼簽章、機器上的代理程式 hook、在路徑上遮蔽系統執行檔的工具,諸如此類。12

雲端那一半如何處理這些資料,說起來很簡單。它依嚴重程度(critical、high、medium)與類別產生發現,對於嚴重等級的發現,它會先嘗試行動,再通知任何人:當一個位址佔了足夠多的事件時,它會把該位址加入一份全帳號的封鎖清單,由每個區域在 edge 上強制執行,為期七天。124 在11月1日的變更之前,每一次這樣的行動也都會產生一封電子郵件;每一筆未被「每個網站、每個類別兩小時一封」限制抑制的嚴重警報、每一個工作階段的結束,以及每一個封鎖量大的小時,也都會。185 本機掃描器產生自己的發現,並自行寄出它的嚴重警報。25 Cloudflare 自己的 Alerts 分成兩種,「Monitors that you define yourself, and Platform Notifications」(您自行定義的 Monitors,以及 Platform Notifications):排程執行的 SQL API 查詢,以及預先設定好的產品警報,兩者都在它的儀表板中設定。26 我的兩者都不是:它是我 Mac 上一支自行讀取防火牆事件的腳本,這也意味著雜訊得由我自己修。

3. 文獻早已說過的事

以下沒有一樣是新的,這才是令人不安的地方。其中大部分我都讀過,卻還是做出了一個逐事件寄信的監控程式。

三種輸出,而電子郵件不在其中。 Google 的 Site Reliability Engineering(《網站可靠性工程》)導論寫道「There are three kinds of valid monitoring output」(有效的監控輸出有三種):警報,「Signify that a human needs to take action immediately」(表示有人需要立即採取行動);工單,「Signify that a human needs to take action, but not immediately.」(表示有人需要採取行動,但不必立即);以及日誌,「No one needs to look at this information, but it is recorded for diagnostic or forensic purposes.」(沒有人需要看這些資訊,但為了診斷或鑑識目的而記錄下來)。7 同一頁對我當時的設計毫不客氣:「a system that requires a human to read an email and decide whether or not some type of action needs to be taken in response is fundamentally flawed.」(一個需要人去讀電子郵件、再決定是否需要採取某種回應行動的系統,從根本上就有缺陷。)7 照這樣分類,我那55封逐筆封鎖郵件,是以警報形式送達的日誌。edge 已經行動了;沒有留下任何需要人去做的事。

每一次呼叫都應該是可採取行動的。 同一本書中 Rob Ewaschuk 撰寫的監控章節,把警報定義為「A notification intended to be read by a human and that is pushed to a system such as a bug or ticket queue, an email alias, or a pager」(一則打算給人閱讀、並推送到錯誤或工單佇列、電子郵件別名或呼叫器等系統的通知),而它關於電子郵件這一類的註腳寫著「Sometimes known as “alert spam,” as they are rarely read or acted on.」(有時被稱為「警報垃圾郵件」,因為它們很少被閱讀或處理)。9 這一章關於呼叫的規則三行就說完了:「Every page should be actionable.」「I can only react with a sense of urgency a few times a day before I become fatigued.」「If a page merely merits a robotic response, it shouldn’t be a page.」(每一次呼叫都應該是可採取行動的;我一天只能帶著緊迫感反應幾次,之後就會疲乏;如果一次呼叫只值得機械式的回應,它就不該是一次呼叫。)8 我對逐筆封鎖郵件的機械式回應,就是刪掉它。這一章也點出了雜訊的代價:「When pages occur too frequently, employees second-guess, skim, or even ignore incoming alerts, sometimes even ignoring a “real” page that’s masked by the noise.」(當呼叫太頻繁時,員工會起疑、草草瀏覽,甚至忽略進來的警報,有時連被雜訊掩蓋的「真正」呼叫也一併忽略。)27 它還描述了一個團隊,「spent significant amounts of time triaging the alerts to find the few that were really actionable」(花了大量時間分流警報,只為找出少數真正可採取行動的那幾筆),這正是我11月1日下午的寫照。28

症狀優先於原因,以及呼叫的檢驗標準。 Ewaschuk 更早的一篇文章,他說那是該章節的基礎,把檢驗標準濃縮成一句話:「Pages should be urgent, important, actionable, and real.」(呼叫應該緊急、重要、可採取行動,而且真實。)29 關於原因,它寫道「Include cause-based information in symptom-based pages or on dashboards, but avoid alerting directly on causes」(把原因層面的資訊放進以症狀為基礎的呼叫或儀表板中,但避免直接針對原因發出警報),所在的小節標題是「Cause-based alerts are bad (but sometimes necessary)」(以原因為基礎的警報不好,但有時必要)。29 我把防火牆封鎖讀成原因層級的事實:一台掃描器打中了一條規則。我在意的症狀,是某條敏感路徑被成功回應,或某個網站掛掉;依我的解讀,那74封沒有一封回報了其中任何一種;當天的探測路徑請求中,沒有任何敏感路徑回傳2xx。3 這篇文章也預見了摘要:「A daily (or more frequent) report can work too」(每日或更頻繁的報告也行得通),並警告「without a system of accountability this amounts to less-spammy email alerts」(若沒有問責機制,這不過是沒那麼像垃圾郵件的電子郵件警報)。30 他的補救之道是一個人:「make sure the oncall person (or someone else) is designated to triage these every day」(確保值班人員或其他人被指定每天分流這些報告)。30 在一個人的監控程式上,那個人只能是我。第4節的處置結果欄位是我自己的輔助機制,不是他的:它讓每天的分流有東西可以核對,也就是每一筆嚴重警報最後怎麼了,但它並不代替分流本身。

精確率與召回率。 The Site Reliability Workbook(《網站可靠性工作手冊》)中關於警報的章節,提供了描述問題所需的詞彙。精確率是「The proportion of events detected that were significant.」(偵測到的事件中,屬於重要事件的比例。)召回率是「The proportion of significant events detected.」(重要事件中,被偵測到的比例。)31 我沒有測量監控程式的召回率,那需要一個它漏掉的重要事件的計數,而第5節就描述了一個它漏掉的事件。作為一條郵件串流,它的精確率接近零:74封電子郵件,依我的解讀,其中沒有一封要求我做任何事。同一章還定義了重置時間:「How long alerts fire after an issue is resolved. Long reset times can lead to confusion or to issues being ignored.」(問題解決後警報還持續觸發多久;過長的重置時間可能導致混淆或問題被忽略。)31 重置時間是為持續觸發的警報定義的;逐筆封鎖郵件只觸發一次,之後不再帶來任何解除的更新:它從不告訴我掃描器已經離開。

同一種失敗的醫院版本。 SRE 的這一章本身就指向軟體以外的領域,指向心臟監測警報管理,「for an example of alert fatigue in another context.」(作為警報疲勞在另一個情境中的例子。)28 The Joint Commission 於2013年4月8日發布、關於醫療器材警報安全的 Sentinel Event Alert(警訊事件警示),為此給出了數字:「The number of alarm signals per patient per day can reach several hundred」(每位病患每天的警報訊號可達數百次),以及「It is estimated that between 85 and 99 percent of alarm signals do not require clinical intervention」(據估計,85%到99%的警報訊號不需要臨床介入)。10 這份警示嚴謹得值得效法:85%到99%涵蓋的是不需要介入的警報,不只是誤報,而警示並沒有把兩者分開。它記錄的後果,正是我已經陷進一半的那種:臨床人員「become desensitized or immune to the sounds」(對聲音變得麻木或免疫),而且「may turn down the volume of the alarm, turn it off, or adjust the alarm settings outside the limits that are safe and appropriate for the patient」(可能調低警報音量、關掉警報,或把警報設定調到超出對病患安全且適當的範圍)。10 它統計了2009年1月至2012年6月間98起與警報相關的事件,其中80起「resulted in death」(導致死亡),並且在通報到其資料庫的因素之外,把警報疲勞列為「the most common contributing factor.」(最常見的促成因素。)10 我的風險低得多。機制卻相同:一個人一旦學到警報不需要他,對下一個真正的警報也會這樣想。

NIST,當年與現在。 NIST 事件處理指南2012年的修訂版 SP 800-61r2 曾警告:「it is not uncommon for an organization to receive thousands or even millions of intrusion detection sensor alerts per day.」(一個組織每天收到數千甚至數百萬則入侵偵測感測器警報並不罕見。)32 2025年4月的修訂版 SP 800-61r3「supersedes SP 800-61r2」(取代 SP 800-61r2),刪去了那句話;它最接近的一句是一項建議:「The volume of potentially adverse events to be analyzed is generally quite high, so organizations should rely on technical solutions that filter large event datasets down to a subset that is suitable for human viewing and analysis.」(需要分析的潛在不利事件數量通常相當高,因此組織應依賴技術方案,把大型事件資料集篩選成適合人工檢視與分析的子集。)33 我把「篩選」當成指示,把摘要當成其中一種做法。

一份廠商調查,就標明是一份。 Vectra AI 的2023年調查由 Sapio Research 執行,涵蓋2,000名資安分析師,報告指出「SOC teams receive an average of 4,484 alerts per day, and over two-thirds (67%) of them are ignored.」(SOC 團隊平均每天收到4,484則警報,其中超過三分之二,即67%,被忽略。)34 這是一份廠商委託的意見調查,67%是受訪者自己說的,不是測量值。我引用它只為一點:這種失敗會向下擴展。分析師說他們忽略了每天4,484則警報中的三分之二,而一個沒有團隊的讀者,在74封時就不再讀了。

4. 重新設計,寫成規則

這項變更在11月1日13:50上線,距離我的訊息18分鐘;14:00的第二項變更收緊了其中一個條件。18 我把它寫成規則,每條都附上它存在的理由。

規則1:每天一封摘要,而它就是心跳訊號。 當地時間07:00之後的第一次監控執行,會寄出一封電子郵件,涵蓋自上一封摘要以來的時間窗。1835 摘要程式自己的說明交代了這封電子郵件取代了什麼:「One email a day … in place of an email per auto-block and per WAF-handled CRITICAL.」(每天一封電子郵件……取代每次自動封鎖一封、每筆由 WAF 處理的嚴重警報一封。)35 它以執行健康狀況開頭(記錄到的執行次數、開始與完成的執行、失敗次數、寄出與被抑制的嚴重警報郵件),接著是附上區域、原因與網路營運商的自動封鎖,每一筆嚴重警報及其最後的處置,依嚴重程度與類別分列的發現,被探測的路徑,以及本機掃描器尚未解決的發現。12 做摘要的理由是收件匣。每天寄出的理由,也寫在同一段說明裡:「The digest is also the heartbeat: it goes out on a quiet day too」(摘要同時也是心跳訊號:平靜的日子它也會寄出)。35 一條只在有事發生時才出聲的警報串流,無法讓我分辨平靜的一天和一個已經死掉的監控程式。一封每天必到的摘要可以:沉默代表故障,而不是平靜。程式自己的筆記記下了我在意這件事的原因:2026年稍早,監控程式曾經死了好幾個月,卻沒有任何東西察覺。35

規則2:封鎖發到聊天頻道,不發郵件。 設計筆記用四個字交代:「Per block: Slack only.」(每次封鎖:只發 Slack。)3 一次封鎖,是 edge 代替我行動。用 SRE 書的術語,它是日誌:記錄下來、日後有用,而且沒有任何需要人採取行動的地方。7 聊天頻道保留即時串流,供我想盯著看的時候使用,摘要則保留紀錄。

規則3:edge 已經處理的嚴重警報,併入摘要。 嚴重警報仍然會先嘗試封鎖;接著監控程式才決定它是否值得一封電子郵件。3 有兩個條件會讓它改為併入摘要,依此順序檢查。第一個:該發現自身的位址,以及其中每一個符合自動封鎖資格的位址,都已在有效的封鎖清單上,因此 edge 此刻正在擋下這些位址。314 這項檢查不看其他任何位址,而且在檢查樣本之前執行,所以被它併入的洪泛,仍可能包含沒有記錄到封鎖或質詢的事件,來自未達封鎖門檻的位址;這個分支說的是回應程式的目標已被封鎖,而不是每一個事件都已緩解。第二個條件適用於 WAF 洪泛,也就是單一區域上一陣密集的防火牆事件:只有當樣本中的每一個事件,無論是不是機器人,都記錄到封鎖或質詢,而且樣本完整時,才會併入。「A solved or bypassed challenge, log, allow and skip all count as unmitigated.」(被解開或繞過的質詢、log、allow 與 skip,都算作未緩解。)3 Cloudflare 的定義正是這四者不利於併入的原因:在質詢之後,「If successful, Cloudflare accepts the matched request」(若成功,Cloudflare 會接受相符的請求),而 log 動作只會「Records matching requests in the Cloudflare Logs.」(把相符的請求記錄在 Cloudflare Logs 中。)36 持續性掃描器的發現只計算 edge 封鎖或質詢過的事件,因此依 WAF 併入條件併入;若其位址已在清單上,則依封鎖清單併入條件併入,11月2日那一筆就是如此。3 其他任何情況都會立即寄信。

規則4:處置結果寫在發現上。 政策是:雲端那一半的每一筆嚴重警報都帶有一個記錄下來的處置結果:因位址已在封鎖清單上而併入、因 edge 封鎖或質詢了每一個取樣事件而併入、已寄信、已抑制(在每個網站、每個類別每兩小時一封的限制之內),或寄信失敗。337 紀錄沒有完全達到政策。在依 UTC 日期屬於11月1日的嚴重警報中,有118筆沒有處置結果:117筆產生於這個欄位存在之前,另有一筆雲端嚴重警報,時間是14:13 PST,晚於欄位上線;它所屬的執行,是第7節提到的、在開始約四分鐘後就結束的三次執行之一,在自動封鎖進行中停止,來不及寫下處置結果。本機掃描器的嚴重警報從來不帶處置結果;11月2日的三筆都沒有。3738 自11月3日起,監控程式會在自動封鎖執行之前,先在嚴重警報上寫下「pending」(處理中),因此中途被切斷的執行會留下可見的狀態,而不是一片空白。14 摘要在每一筆雲端嚴重警報旁印出處置結果,標題本身就做出承諾:「Every CRITICAL and what became of it」(每一筆嚴重警報及其後來的處置)。12 處置結果欄位是我的機制,不是 Ewaschuk 的。他對每日報告的條件,是指定一個人每天分流它,而在這裡那個人就是我;這個欄位讓分流有東西可以核對。30 每一行都有處置結果之後,摘要便能一筆一筆回答我11月1日提出的問題:例行,還是真的?不過「emailed」(已寄信)或「folded」(已併入)說的是一筆嚴重警報去了哪裡,而不是有任何事情已經解決。

規則5:每小時流量警報保留。 再引一次筆記:「Hourly volume alert (responder): still immediate, at most once an hour」(每小時流量警報(回應程式):仍然立即寄出,每小時最多一次)。3 單一封鎖是例行公事;一個小時內突然堆出一大堆封鎖,則是雲端那一半最接近「症狀」的東西:網際網路對我所做的事情起了變化。它在11月2日觸發了一次。5

規則6:本機掃描器的嚴重警報仍然立即寄信。 設計筆記讓它們保持立即,因為它們本來就應該很少見。3 我保留它們還有第二個理由:在我的 Mac 與本機發現之間,沒有任何東西像 edge 擋在我的網站與掃描器之間那樣擋著。封鎖清單可以擋下一個位址;Mac 之外沒有任何東西能擋下 Mac 上的一個行程。這條規則的代價,會在第7節出現。

規則上線的那一天,郵件串流從13:32之前的74封,降到當天剩餘時間日誌記錄的七封(六封嚴重警報、一封每小時警報),再加上我手動寄出的那封摘要。52 我那天下午寫下的預測說:「Under today’s traffic that would have been 0 immediate emails instead of 16.」(以今天的流量來看,立即寄出的電子郵件會是0封,而不是16封。)1 這個預測沒有成立,第6節會說明原因。

5. 測試案例:11月2日,11:03至11:21

這些規則的第一次真正測試,在隔天早上到來:一家荷蘭主機代管業者名下的一個位址,對我的網站跑了一台弱點掃描器。12 以下是監控程式寫下的內容,逐字取自它的日誌,時間為當地太平洋時間,位址以「[the address]」取代,中間的行省略。4

[2026-11-02 11:03:53] [INFO] New finding [critical]: Request flood from [the address] on blakecrosley.com
[2026-11-02 11:04:02] [RESPOND] [INFO] Block notification: Slack posted, email folded into the daily digest
[2026-11-02 11:04:03] [INFO] Critical alert folded into the daily digest (IP on the block ledger): Request flood from [the address] on blakecrosley.com
[2026-11-02 11:04:04] [INFO] New finding [critical]: Scanner from [the address] on blakecrosley.com
[2026-11-02 11:04:05] [RESPOND] [INFO] Skip: [the address] already has active real block in blakecrosley.com (dedup)
[2026-11-02 11:04:05] [INFO] Critical alert folded into the daily digest (IP on the block ledger): Scanner from [the address] on blakecrosley.com
[2026-11-02 11:09:22] [INFO] New finding [critical]: 726 WAF blocks in 5 minutes
[2026-11-02 11:09:23] [INFO] Critical alert folded into the daily digest (IP on the block ledger): 726 WAF blocks in 5 minutes
[2026-11-02 11:09:44] [INFO] New finding [critical]: Persistent scanner: [the address] blocked 743 times today
[2026-11-02 11:09:47] [RESPOND] [INFO] Block notification: Slack posted, email folded into the daily digest
[2026-11-02 11:09:47] [INFO] Critical alert folded into the daily digest (IP on the block ledger): Persistent scanner: [the address] blocked 743 times today

逐分鐘來看:

  • 11:03:53。 請求洪泛偵測器針對該位址產生一筆嚴重警報。八秒後,11:04:01,回應程式把它加入封鎖清單;11:04:02,封鎖通知發到聊天頻道,它的電子郵件則併入摘要。4
  • 11:04:03。 嚴重警報本身併入:位址現在已在封鎖帳本上,所以 edge 已經在做一封電子郵件會要求我去做的事。4
  • 11:04:04。 第二個偵測器,也就是掃描器檢查,對同一個位址產生自己的嚴重警報。回應程式的封鎖請求因重複而被略過,這筆嚴重警報在一秒後併入。4
  • 11:09:22。 WAF 洪泛偵測器針對該區域產生第三筆嚴重警報。它的肇事者已在帳本上,於是併入。411 決定這件事的只有封鎖清單這個併入條件:取樣事件中有八個沒有記錄到封鎖或質詢,而且樣本已達上限,所以單憑 WAF 併入條件,它會被寄出。11
  • 11:09:44。 持續性掃描器檢查,計算 edge 在我所有區域上對單一位址封鎖或質詢過的事件,產生第四筆,記錄在我的另一個網站上:該位址當天有743個被封鎖或質詢的事件。12 回應程式第二次把該位址寫入清單(一個缺陷,見下文),貼到聊天頻道,並在11:09:47把這筆嚴重警報併入。411
  • 11:14:58與11:20:40。 同一個區域又有兩筆 WAF 洪泛嚴重警報;兩筆都以同樣方式併入。11

5分51秒內四筆嚴重警報,到11:20共六筆,在各自的發現上都記錄為「因位址已被封鎖而併入」。11 一個位址被封鎖,它的清單項目被寫了兩次,因為當時的重複檢查是以網站為單位運作(11月3日已修正),另有四次封鎖請求因重複而被略過。414 電子郵件:零封。日誌顯示11:03到11:21之間沒有寄出任何電子郵件;該時間窗內唯一既沒有併入、也沒有寄信的嚴重警報,在11:03:13被抑制,那是另一個網站上、來自另一個位址的洪泛。4

下一封摘要把這件事呈現為自動封鎖表中的兩列(第一次封鎖,附上區域、原因與網路營運商,以及持續性掃描器的重新加入),以及全部嚴重警報表中的六列,每一列都標著「blocked」(已封鎖)或「blocked earlier」(先前已封鎖)。12 依我的解讀,對一台在第一筆發現後八秒、掃描開始後八分鐘就被監控程式封鎖的掃描器而言,這是恰當的分量:幾行配咖啡就能讀完的文字,而不是一次半夜把人叫醒的呼叫。4

有一件事是這個測試案例沒有呈現的,於11月3日發現。同一台掃描器也在對我網站的聯絡表單送出內容,我的應用程式對這些送出都回應了200,因此它們本身最多讓我收到31封電子郵件,也是姊妹篇文章的主題;而監控程式的表單洪泛檢查在即時執行中沒有產生任何發現。若在完整資料上重播截至11:03:23的那五分鐘,同一項檢查會產生這筆發現,嚴重程度為 high(只是摘要中的一行,不是電子郵件也不是封鎖),依據是39次送出,其中23次被拒絕。39 即時執行向 Cloudflare 查詢的時間窗,結束於它發出查詢的那一刻,也就是執行開始後37秒,在最新的事件完全抵達之前:它在該時間窗內計得該位址的請求為1,914個,而在完整資料上的重播計得2,143個。439 這個延遲是在該位址的全部請求上量得的,而不是在這項檢查計算的表單送出上;依我的解讀,同樣的延遲讓那些送出在即時執行中停留在檢查門檻之下。此外,每次執行都恰好往回看五分鐘,而各次執行的開始時間相隔約5.6到5.8分鐘,所以每個間隔都有一部分從未被掃描到。3917 修正在同一天上線:現在每個時間窗從上一個時間窗結束處開始,並在執行前90秒結束;除非上一筆紀錄不存在、不到一分鐘,或超過15分鐘(例如 Mac 睡眠之後),這時執行會退回單純往回看五分鐘的做法。39 用修改後的程式碼重播11月2日的那個時間窗,得到相同的發現,所以這項變更沒有干擾固定時間窗上的偵測。重播無法驗證時間窗銜接或延遲,因為它們只作用於即時執行;11月3日以後的即時執行,才是它們的測試。39

6. 仍然會寄信的,以及原因

11月2日是新規則下的第一個完整日,它寄出了19封電子郵件,而不是一封:14封嚴重警報、一封每小時流量警報、一封摘要,以及三封來自本機掃描器。5 沒有任何逐筆封鎖郵件寄出;108則封鎖通知改為併入摘要,177筆嚴重警報被併入,另有37筆被兩小時限制抑制,以上皆依當地日期計算;本文稍後的處置結果計數則依 UTC 日期計算,所以那些數字有所不同。5

依串流統計每個當地日期電子郵件數的堆疊長條圖。10月31日,從22:31開始的不完整一天:10封電子郵件,4封逐筆封鎖、6封嚴重。11月1日:82封,包含55封逐筆封鎖、22封嚴重、3封每小時流量、1封手動寄出的摘要,以及1封來自本機掃描器。11月2日:19封,包含14封嚴重、1封每小時流量、1封摘要,以及3封來自本機掃描器,沒有任何逐筆封鎖郵件。

依串流統計每個當地日期的電子郵件數;10月31日只涵蓋日誌開始後的89分鐘。5

從13:50的變更之後到11月2日結束,每一筆寄出電子郵件的雲端嚴重警報,共20筆(11月1日剩餘時間六筆,11月2日十四筆),都是 resumegeni.com 或 blakecrosley.com 上的 WAF 洪泛,其中至少有一個事件沒有記錄到封鎖或質詢。13 WAF 併入條件依它自己的規則,正確地拒絕了每一筆:樣本中有一個未緩解的事件,所以監控程式無法斷言 edge 已經處理了它。3 在那些洪泛中,沒有任何位址的事件數足以符合自動封鎖資格,所以封鎖清單併入條件沒有位址可以核對。13 摘要也以同樣的方式稱呼這一組:「a CRITICAL that was neither blocked nor already handled by the WAF」(既沒有被封鎖、也沒有已由 WAF 處理的嚴重警報)。12

那些電子郵件的主旨說的卻是另一回事,而這是一個缺陷。洪泛摘要寫的是「N WAF blocks in 5 minutes」(5分鐘內 N 次 WAF 封鎖),但 N 計算的是時間窗內每一個非機器人的防火牆事件,無論 edge 對它採取了什麼動作。13 以下是發現中的兩個例子,當地時間:

時間(PT) 網站 主旨寫的是 已封鎖 已質詢 未緩解
11月1日,16:51 blakecrosley.com 「104 WAF blocks in 5 minutes」 0 0 117個事件中的117個
11月1日,22:45 resumegeni.com 「108 WAF blocks in 5 minutes」 18 62 179個事件中的99個

第一封電子郵件聲稱封鎖了104次,而 edge 實際上什麼都沒有封鎖。13 依我的解讀,一個在沒有記錄到封鎖的事件上寫著「blocks」的主旨,比雜訊還糟:它告訴唯一的讀者,系統已經處理了它可能並未處理的東西。我在11月3日、也就是完成這些計數的那天所做的第一次修正,本身就是錯的。它保留了非機器人計數作為 N,卻在所有事件上計算已封鎖、已質詢與其餘事件,所以16:51那一陣會寫成 104 WAF events in 5 minutes: 0 blocked, 0 challenged, 117 through,一行裡有兩個母體。這篇文章的審查抓出了這一點,我在同一天又修正了一次。14 洪泛摘要,連同電子郵件主旨,現在只計算一個母體,也就是每一個取樣的防火牆事件,寫作 N WAF events in 5 minutes: B blocked, C challenged, U unmitigated (S from non-bot user agents);JavaScript 質詢算作已質詢,自動封鎖的原因則寫作 N WAF events from this address in 5 min。14 以16:51那一陣為例,結果是 117 WAF events in 5 minutes: 0 blocked, 0 challenged, 117 unmitigated (104 from non-bot user agents)。1314 WAF 併入條件本來就是以未緩解事件為準,所以現在主旨和決策計算的是同一件事。這項修正改變的是那14封的主旨寫什麼,並沒有改變寄出了多少封,19仍是11月2日誠實的數字。

我在11月1日寫下的預測之所以落空,是因為它的前提錯了。它說新規則「would have been 0 immediate emails instead of 16」(立即寄出的電子郵件會是0封,而不是16封),依據的信念是:對當天早上00:30之後的七筆嚴重警報而言,「Cloudflare had already blocked every one of those requests.」(Cloudflare 早已封鎖了那些請求中的每一個。)1 對那幾筆,發現同樣給出不同的答案:日誌顯示00:30之後寄出的五筆,每一筆最多記錄了一次封鎖和九次質詢,而它們摘要中的事件數是76到89個。13 而在當天下午和晚上寄出的六筆嚴重警報中,每一筆的 edge 都只封鎖或質詢了部分事件(16:51那一陣則完全沒有),所以即使是13:50的規則,也就是只有在封鎖與質詢涵蓋每一個非機器人事件時才併入的那條,也會把每一筆都寄出。131 13:50變更後十分鐘,第二項變更讓 WAF 併入條件計算每一個事件,無論是不是機器人使用者代理,並且只信任完整的樣本;它讓規則更嚴格,但這不是預測落空的原因。183 預測計算的是我相信存在的封鎖;規則計算的是實際存在的事件。

我不知道的是,那14封,也就是11月2日寄出電子郵件的嚴重警報,是否值得一封電子郵件。發現記錄了有多少事件未緩解,也就是沒有記錄到封鎖或質詢,但沒有記錄它們帶有什麼動作:一條 log 規則、一個 skip、一個 allow,或一個被用戶端解開的質詢。13 一個未緩解的事件,也不等於一個抵達我網站的請求。Cloudflare 說「A single HTTP request can generate one or more security events when it triggers security features」(單一 HTTP 請求在觸發安全功能時,可能產生一個或多個安全事件),並把 log 和 skip 列為不會像封鎖那樣結束規則評估的動作,所以依我的解讀,另一條規則仍可能對同一個請求採取行動。2436 Cloudflare 的 GraphQL 教學展示了 action 欄位以及 "log" 和 "block" 這類範例值,但沒有列出該欄位所有可能的值。23 Cloudflare 的 Security Events 儀表板也會取樣:「For large volumes of traffic, Cloudflare uses sampling to return results faster.」(對於大量流量,Cloudflare 會使用取樣以更快回傳結果。)24 在監控程式記錄每一個未緩解事件背後的動作、並把事件與請求對應起來之前,我無法說出那些電子郵件中,哪些描述的是 edge 放行的流量,而這個答案決定了它們是否值得一封電子郵件。

11月2日的三封本機電子郵件是另一個懸而未決的項目。它們回報13:50的一條「Browser -> shell chain」(瀏覽器到 shell 的鏈),其中一個 shell 啟動了 curl,而它們在發現中仍未解決。40 我還沒有驗證它們是我那天下午在跑的代理程式工具,還是別的東西,所以我不把它們算作誤報。

7. 兩個錯誤的訊號

原來是 Spotlight 的加密貨幣挖礦程式

11月1日10:03,本機掃描器產生一筆嚴重警報,「High CPU unsigned process - possible crypto miner」(高 CPU 的未簽署行程,可能是加密貨幣挖礦程式),對象是 spotlightknowledged,也就是 Apple 自家的 Spotlight 常駐程式,CPU 使用率74.9%;兩秒後,日誌記下「Critical email sent.」15 錯在我。這項檢查在程式碼簽章顯示指令 codesign -d 的輸出中尋找「valid on disk」這個片語。掃描器的筆記現在用一個子句記下這個瑕疵:這個片語是「which only codesign -v prints, so every process read as unsigned」(只有 codesign -v 才會印出的,所以每一個行程都被讀成未簽署)。25 一份略過清單一直掩蓋著這個瑕疵,直到一個 Apple 框架常駐程式的 CPU 飆高為止,我當天的日誌也這麼寫。1 這筆發現現在帶有它的解決說明:「false positive, Apple platform binary」(誤報,Apple 平台執行檔)。41

它的代價是一封電子郵件,也是11月1日唯一的一封本機郵件。5 在它之前,10月31日與11月1日的16筆本機嚴重警報,標記了 Xcode、Homebrew 的 Python、我自己的 App 建置、hook 的變更、路徑上的版本管理器 shim、一個比對到另一個專案代理程式指示的 AI 蠕蟲模式,以及一個比對到自己查詢的事件監聽(event tap)檢查;它們產生了15次寄送嘗試,而每一次都失敗了。5251915 郵件服務位於 Cloudflare 之後,而 Cloudflare 在讀取金鑰之前,就以錯誤1010回應了 Python 預設的使用者代理;我用一把故意給錯的金鑰重現了這個情況。19 Cloudflare 針對這個錯誤的頁面,在關於 Pages 與 Workers 主機的說明中,直接點名了這種用戶端:「a User-Agent header that Browser Integrity Check treats as a non-browser client (for example, the default Python urllib user agent).」(一個被 Browser Integrity Check 視為非瀏覽器用戶端的 User-Agent 標頭,例如 Python urllib 預設的使用者代理。)42 一個壞掉的寄件程式,讓我免於收到15封關於我自己的工具和我自己的變更的電子郵件。15 掃描器的筆記把更大的教訓說得很直白:「most of the CRITICALs it raised in its first live days were its own noise.」(它在上線最初幾天產生的嚴重警報,大多是它自己的雜訊。)25 我仍然讓本機嚴重警報保持立即寄出,並且在每一個誤報的檢查本身修正它,而不是把整條串流靜音。

RUNS SHORT 162/207

第一封排程寄出的摘要,在11月2日早上,主旨是「Mon Nov 2: 71 blocks on 15 zones, 11 criticals emailed, RUNS SHORT 162/207」(11月2日週一:15個區域上71次封鎖,11筆嚴重警報已寄信,執行次數不足162/207)。16 摘要的規則是簡單的算術:預期執行次數等於時間窗的分鐘數除以五,主旨會標出短缺。35 時間窗從11月1日13:48到11月2日07:05,共1,036.5分鐘,也就是207個五分鐘時段;日誌記錄了162次執行。17

我11月2日的日誌用一行解釋了這個落差:「The RUNS SHORT line is the Mac asleep」(RUNS SHORT 那一行是因為 Mac 在睡眠),監控程式沒有故障。43 那一行說監控程式沒有失敗是對的(11月2日沒有任何一次執行未完成),但對原因的判斷是錯的,無論是就11月2日當天,還是就那個數字所描述的時間窗而言。執行間隔分析把缺少的45個時段大致拆分為:約25個損失在執行節奏上,約16個在睡眠上,約一個在一次提早結束的執行之後的長間隔中,還有三次從未記錄自己的執行。17

原因 時段數(約) 證據
實際的執行節奏 25 160個一般的執行間隔,中位數5.60分鐘,從未低於5.35;合計926.0分鐘,即185個五分鐘時段
睡眠 16 三個超過10分鐘的間隔,共93.0分鐘,落在電源日誌的閒置睡眠期間內,執行在短暫的維護喚醒期間恢復
提早停止後的長間隔 1 第四個超過10分鐘的間隔,在14:19那次提早結束的執行之後,為10.0分鐘
從未記錄自己的執行 3 165次執行開始,對照162次記錄到的執行
這三次背後 三次執行在開始約四分鐘後結束,沒有記錄任何結束行,從時間點判斷是240秒的看門狗,全部發生在11月1日:下午兩次,當晚稍晚一次

電源日誌顯示23:21:30進入閒置睡眠、00:30:05完全喚醒,以及06:01:20再次進入閒置睡眠、06:30:28完全喚醒。44 那三次執行分別在11月1日14:09、14:19與23:10開始;每一次都在約四分鐘後結束,沒有記錄任何結束行,依我的解讀,這是240秒的看門狗。第四次執行在開始28秒後結束,看不出原因。1738 就11月2日這個日曆日而言,對照288個五分鐘時段,共有242次執行開始,短少46次,沒有任何一次未完成;只有兩個間隔超過10分鐘,共35.8分鐘,所以那一天大部分的短缺同樣來自執行節奏,而不是睡眠。17

錯誤的假設是我的,寫在摘要裡:一個設定為五分鐘的排程器,即使在 Mac 醒著的時候,也大約每5.6到5.8分鐘才交付一次執行,所以五分鐘的算術會把健康的一天判定為短缺。17 我還沒有查明醒著時的執行節奏為什麼會偏慢。我在11月3日換掉了這套算術。執行健康狀況現在回報記錄到的執行次數、執行之間的中位分鐘數,以及最長的間隔及其時間,而主旨只在間隔超過20分鐘時才標記。那天早上的預覽寫著「about one every 5.6 min」(大約每5.6分鐘一次),主旨結尾是「RUN GAP 31 min at 05:56」(05:56出現31分鐘的執行間隔)。14 間隔是我可以採取行動的症狀:Mac 睡著了,或監控程式停了。一個以排程器從未交付過的節奏為分母的比率,兩者都不是。

我保留的規則

  1. 改變郵件之前先計數,依串流計數,並寫明規則。 我的表格和日誌計數之所以都是74,只因為我先寫下了什麼算一封電子郵件。12
  2. 只有在郵件服務回答「好」時,才記錄「sent」。 我的74封中有22封,我能證明的只有一次嘗試,其他一概不能。26
  3. edge 已經執行的封鎖是一行日誌,不是警報。 SRE 書的三種輸出把它放在那裡,而把55封逐筆封鎖郵件移到聊天頻道,並沒有讓我失去任何曾據以行動的東西。75
  4. 即使什麼都沒發生,也要寄出每日摘要。 一封每天必到的摘要就是心跳訊號;它的缺席本身就是警報。35
  5. 只有在 edge 能證明的條件下,才併入嚴重警報。 我的條件是:該發現中可封鎖的位址已在封鎖清單上;以及一個完整的樣本,其中每一個事件都記錄到封鎖或質詢。第二個條件,正是11月2日仍有14封寄出的原因。313
  6. 在每一筆雲端嚴重警報上寫下處置結果。 一份沒有人負責的每日報告,用 Ewaschuk 的話說,就是「less-spammy email alerts」(沒那麼像垃圾郵件的電子郵件警報);每一行上的處置結果,就是我每天分流時核對的東西。3012
  7. 讓主旨說出 edge 做了什麼。 在一陣零封鎖的事件上寫「104 WAF blocks」,是我這一週寫過最糟的一行。13
  8. 回報間隔,而不是對照排程的比率。 一個五分鐘的計時器大約每5.6分鐘才交付一次執行,所以162/207看起來像停機,其實大部分只是時鐘的問題。17
  9. 在檢查本身修正誤報,而不是在收件匣。 一次誤讀的指令輸出,讓 Apple 的 Spotlight 常駐程式變成了加密貨幣挖礦程式;修正放進了檢查裡。25

可能改變的情況

  • 如果未緩解的事件最後證明是被解開的質詢, 光憑這一點,並不會讓仍在寄信的 WAF 洪泛嚴重警報變成雜訊。當用戶端通過質詢時,「Cloudflare accepts the matched request」(Cloudflare 會接受相符的請求):請求繼續進行,而這並不能證明請求無害,也不能證明不需要任何回應。要併入這些嚴重警報,需要與相同事件對應的請求證據,顯示其中沒有任何東西需要人處理,而單憑質詢完成並不構成這樣的證據。如果它們最後證明是 log 或 skip 規則,問題就在於這些規則是否照我的本意運作,而在我弄清楚之前,每一封電子郵件都值得一讀。監控程式目前還沒有記錄是哪一種。1336
  • 如果某一天的嚴重警報郵件又爬回幾十封, 那就表示每個網站、每個類別的兩小時限制在做一條規則該做的事,而那條規則需要重新檢視。3
  • 如果摘要不再送達, 那就表示監控程式與我的收件匣之間有某樣東西停了:監控程式、它所在的 Mac、寄件程式,或遞送路徑,因為一次被接受的寄送還不是一次已送達的寄送。這是這套設計唯一一種會被視為「該去看看」的沉默。3520
  • 如果本機掃描器產生一筆我無法用自己的工具解釋的嚴重警報, 那麼立即寄信就是正確的決定;11月2日那三筆尚未解決的 shell 鏈發現,就是這一點的未決測試。40
  • 如果我增加一位讀者, 呼叫與工單就不再是同一個人,而 SRE 書對警報與工單的區分,就需要一個工單佇列,而不是我的收件匣。7

重點整理

如果您為自己運行一個監控程式

  • 我在半天之內、還不到74封電子郵件時,就已經不再閱讀,而這個數目,我的收件匣在下午稍早就已經達到。1
  • 一封在平靜日子也會送達的每日摘要,就是免費的心跳訊號;一個只在事件發生時才出聲的監控程式,無法告訴您它已經死了。35
  • 您的日誌可能對從未寄出的郵件寫著「sent」。在相信計數之前,先檢查程式碼。619

如果您要打造一個

  • 先行動,再決定要不要通知:先封鎖,然後如果封鎖清單或 edge 已經涵蓋,就把警報併入摘要。3
  • 在發現上記錄每一筆嚴重警報的處置結果,並在摘要中印出來,讓 Ewaschuk 所說必須分流每日報告的那個人有東西可以核對;在我的監控程式上,那個人就是我。3012
  • 依 edge 為事件記錄的內容來命名事件(已封鎖、已質詢、未緩解),一行只計算一個母體,絕不要依您希望 edge 做了什麼來命名。1314
  • 測量您實際擁有的排程器。我的排程器設定為五分鐘的計時器,卻每5.6分鐘才執行一次。17

如果您是讀收件匣的那個人

  • 對每一則警報都問:它是否「urgent, important, actionable, and real」(緊急、重要、可採取行動,而且真實);任何不合格的,都屬於摘要或日誌。29
  • 我第一天的預測落空了:它說立即寄出的嚴重警報是零封,而隔天寄出了14封。15

常見問題

什麼是警報疲勞?

警報疲勞,是指接收太多不需要他們做任何事的警報的人所遭遇的狀態:用 The Joint Commission 的話說,他們變得「desensitized or immune to the sounds」(對聲音麻木或免疫),並開始把警報調小聲或關掉。10 Google 的 SRE 書在維運領域描述了同樣的事,人們會「second-guess, skim, or even ignore incoming alerts, sometimes even ignoring a “real” page that’s masked by the noise.」(起疑、草草瀏覽,甚至忽略進來的警報,有時連被雜訊掩蓋的「真正」呼叫也一併忽略。)27 我自己的案例只花了一天:13:32之前74封電子郵件,依我那天下午的解讀,沒有一封要求我採取行動。1

每天多少則資安警報算太多?

對一個人而言,SRE 那一章誠實的答案是幾則:「I can only react with a sense of urgency a few times a day before I become fatigued.」(我一天只能帶著緊迫感反應幾次,之後就會疲乏。)8 Vectra 的廠商調查指出,團隊平均每天收到4,484則警報,而依他們自己的說法,其中67%被忽略。34 對我一個人的監控程式而言,可行的答案是每天一封摘要,加上那些現在就需要人處理的警報;11月2日這仍然是19封,而其中14封 WAF 洪泛嚴重警報,我把它們視為一個未決的問題,而不是已經確定的成本。513

資安警報應該用每日摘要,還是即時發送?

兩者都要,依人必須做什麼來區分。凡是監控程式認定已經處理的事(它已放上封鎖清單的位址,或每一個取樣事件都被封鎖或質詢的洪泛),都進摘要;其餘的立即寄出,受兩小時限制約束。3 Ewaschuk 承認每日報告「can work too」(也行得通),但有一個條件:若沒有問責機制,它「amounts to less-spammy email alerts」(不過是沒那麼像垃圾郵件的電子郵件警報),而他希望有人被「designated to triage these every day」(指定每天分流這些報告)。30 在我的監控程式上,那個人就是我,而我的摘要會印出每一筆雲端嚴重警報最後怎麼了,讓分流有東西可以核對。12

什麼是心跳警報?

心跳是一則依排程送達的訊息,無論有沒有事發生都會送達,因此它的缺席就代表有東西壞了。我的每日摘要就是心跳訊號:「it goes out on a quiet day too」(平靜的日子它也會寄出),所以一個已經停止執行的監控程式,會表現為一封缺席的電子郵件。35 寄送失敗或遞送遺失也會如此,所以一封缺席的摘要,是去檢查監控程式、它所在的主機、寄件程式與遞送路徑的提示。20 它的執行健康狀況區段也會回報執行之間最長的間隔,並在主旨中標記超過20分鐘的間隔。14

為什麼 Cloudflare WAF 警報會塞爆我的電子郵件?

我的會塞爆,是因為每一次封鎖和每一筆嚴重警報都變成了一則獨立的訊息,而網際網路整天都在掃描每一個公開的區域。5 Cloudflare 自己的 Alerts,「Monitors that you define yourself, and Platform Notifications」(您自行定義的 Monitors,以及 Platform Notifications),可以透過電子郵件遞送,並在它的儀表板中設定;像我這樣自己對著它的 API 打造的監控程式,兩者都不是,並且會繼承您寫進去的任何逐事件寄信邏輯。26 也要檢查一則警報計算的是什麼:Cloudflare 的動作包括 log 和 skip,它們不會像封鎖那樣結束規則評估,而一個被用戶端解開的質詢,結果是 Cloudflare 接受了請求,所以「WAF events」(WAF 事件)和「WAF blocks」(WAF 封鎖)是不同的數字。36 直到11月3日之前,我的主旨一直混淆了兩者。1314

電子郵件 API 回傳2xx,代表警報已經送達嗎?

不代表。Resend 的 email.sent 事件「Occurs whenever the API request was successful. Resend will attempt to deliver the message to the recipient’s mail server」(每當 API 請求成功時發生;Resend 會嘗試把訊息遞送到收件人的郵件伺服器),而遞送是另一個事件。20 2xx 代表服務接受了訊息。記錄狀態碼,並把遞送視為另一個問題。6

本站相關文章:為什麼垃圾訊息打敗了我有速率限制的聯絡表單從聯絡表單的角度追蹤同一台11月2日的掃描器;睡前必跑的那道指令是每晚的正式環境檢查,也是另一個在我沒看著時執行的例行程序;無人監督執行 AI 代理程式時,真正會壞掉的是什麼列出無人看管的代理程式工作階段的各種失敗模式,每一種都附上偵測訊號;每一個 hook 都是一道傷疤把我的每一個代理程式 hook 追溯到催生它的那次失敗,與在檢查本身修正誤報是同一種習慣;Claude Code 的 auto 模式不是安全邊界主張代理程式周圍的那道牆,比它的分類器更重要;AI 代理程式的可觀測性則論證為什麼要看清代理程式對磁碟、CPU 與網路做了什麼。

資料來源

作者自身資料中的所有時間,除標明 UTC 者外,皆為當地太平洋時間;11月1日於02:00從 PDT 回撥為 PST。公開頁面於2026年11月3日擷取,擷取時間以 UTC 標示。


  1. 作者的營運日誌(Captain’s Log),2026年11月1日:太平洋時間13:32的訊息;午夜以來依串流統計的74封電子郵件表格(55封逐筆封鎖、16封嚴重、2封每小時流量、1封本機);13:50的併入規則(封鎖與質詢涵蓋每一個非機器人事件);嚴重警報的分拆「9 before the fold went live at 00:30 PT; the 7 after」,以及「Cloudflare had already blocked every one of those requests」這個信念;「Yesterday had 10」;太平洋時間13:48手動寄出的第一封摘要;預測「Under today’s traffic that would have been 0 immediate emails instead of 16」;以及略過清單掩蓋了程式碼簽章錯誤的記載。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. 作者的資料:以腳本從監控程式日誌推導出的電子郵件計數,截至11月1日太平洋時間13:32:74封(55封逐筆封鎖、16封嚴重、2封每小時流量、1封本機),其中22封(10封逐筆封鎖、11封嚴重、1封每小時)來自無條件記錄「sent」的寄件程式;整個當地日期為81封。同一支腳本的逐行清單顯示,00:30之前有11行嚴重警報「sent」紀錄、之後有5行,而第一筆併入封鎖通知的嚴重警報出現在00:54:43。 ↩↩↩↩↩↩↩↩↩

  3. 作者的監控程式設計筆記,通知一節,截至2026年11月3日:「Every one described routine mass-scanning the edge had already stopped」(每一封描述的都是 edge 早已擋下的例行大規模掃描);「Per block: Slack only」;兩個併入條件及其順序;「A solved or bypassed challenge, log, allow and skip all count as unmitigated」;每小時流量警報保持立即寄出;本機掃描器的嚴重警報因本應罕見而保持立即寄出。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  4. 作者的資料:監控程式2026年11月2日太平洋時間11:03至11:21的日誌:第5節引用的各行(位址已取代)、11:04:01與11:09:46寫入封鎖清單且效期七天、四次被略過的重複封鎖請求、聊天頻道的貼文,以及該時間窗內除了11:03:13另一個網站上一次被抑制的洪泛之外,沒有任何電子郵件紀錄;產生第一筆嚴重警報的那次執行於11:02:46開始,其偵測器時間窗結束於11:03:23,即37秒後,其封鎖原因計得該位址在該時間窗內有1,914個請求。掃描的第一批請求在太平洋時間10:56抵達網站,比封鎖早八分鐘(作者11月2日的營運日誌,以及 Cloudflare 對該位址的逐分鐘請求計數)。 ↩↩↩↩↩↩↩↩↩↩↩↩↩

  5. 作者的資料:以腳本從監控程式2026年10月31日至11月2日的六個日誌(雲端那一半與本機掃描器)推導出的電子郵件計數,每一行記錄一次交付給郵件服務的紀錄計為一封電子郵件。依當地日期:10月31日(日誌從22:31開始),10封(4封逐筆封鎖、6封嚴重,全部來自無條件記錄「sent」的寄件程式;3筆嚴重警報被兩小時限制抑制;13次本機寄送失敗);11月1日,日誌記錄81封(55封逐筆封鎖、22封嚴重、3封每小時流量、1封本機;2次本機寄送失敗),另加一封手動寄出的摘要;11月2日,19封(14封嚴重、1封每小時流量、1封摘要、3封本機)。11月2日未寄信者:108則封鎖通知與177筆嚴重警報併入摘要,37筆嚴重警報被抑制。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  6. 作者的程式碼:監控程式於2026年10月31日啟用時的寄件程式,會丟棄郵件請求的回應,然後無條件記錄「sent」;以及11月1日01:04 PDT、時鐘回撥之前的變更,此後雲端那一半的寄件程式記錄郵件服務的 HTTP 狀態碼,只有在2xx時才寫「sent」;本機掃描器的寄件程式則只寫一行單純的「Critical email sent」,而且只在請求沒有拋出錯誤時才寫。 ↩↩↩↩↩↩

  7. Benjamin Treynor Sloss,“Introduction,”,Site Reliability Engineering: How Google Runs Production Systems(Google 著,O’Reilly Media 出版)第1章,擷取時間14:19:33Z:三種有效的監控輸出(警報、工單、日誌),引文;以及稱「讀電子郵件再決定」式警報為「fundamentally flawed」(從根本上有缺陷)的段落。 ↩↩↩↩↩↩

  8. Rob Ewaschuk,“Monitoring Distributed Systems,”,Site Reliability Engineering(Google,O’Reilly Media)第6章,擷取時間14:18:54Z:「Every page should be actionable」、關於緊迫感的那一句,以及關於機械式回應的那一句,引文。 ↩↩↩

  9. Ewaschuk,“Monitoring Distributed Systems,”,擷取時間14:18:54Z:警報的定義,以及關於電子郵件警報的第22號註腳(「alert spam」),引文。 ↩↩

  10. The Joint Commission,“Medical device alarm safety in hospitals,”,Sentinel Event Alert 第50期,2013年4月8日,讀自 Wayback Machine 於2024年11月13日的存檔,擷取時間14:21:49Z(發布者自己的網址回應403):每位病患每天的警報訊號數;85%到99%的估計,警示將其歸於 AAMI,涵蓋不需要臨床介入的警報,而沒有把誤報區分出來;麻木與調低音量的段落;2009年1月至2012年6月間98起與警報相關的事件,其中80起導致死亡;以及「the most common contributing factor」,引自警示中列於其 Sentinel Event 資料庫通報因素之外的因素清單,該清單與資料庫本身的通報因素清單是分開的。 ↩↩↩↩↩

  11. 作者的資料:監控程式發現檔中,11月2日那台掃描器的六筆嚴重發現(11:03:53請求洪泛、11:04:04掃描器、11:09:22 WAF 洪泛、11:09:44持續性掃描器、11:14:58與11:20:40 WAF 洪泛),每一筆都記錄為因位址已在封鎖清單上而併入;11:09:22那筆 WAF 洪泛也記錄了八個沒有記錄到封鎖或質詢的取樣事件,以及等於監控程式樣本上限的防火牆事件數,因此其樣本已達上限。 ↩↩↩↩↩↩

  12. 作者的資料:摘要程式的預覽模式於2026年11月3日呈現的下一封摘要(時間窗為11月2日週一07:05至11月3日週二06:17 PST;預覽不寄出任何東西):其各區段、本機掃描器的10分鐘分層、在每個區域上強制執行七天的全帳號封鎖清單、附有網路營運商的自動封鎖表(11月2日的掃描器為一家荷蘭主機代管業者)、「Criticals that emailed you」(寄信給您的嚴重警報)標題文字,以及「Every CRITICAL and what became of it」表格。 ↩↩↩↩↩↩↩↩↩↩↩↩

  13. 作者的資料:從11月1日13:50 PST 的變更(處置結果欄位自此開始)到11月2日 PST 結束,每一筆記錄為已寄信的嚴重警報,共20筆(15筆的 UTC 日期為11月1日與2日,5筆的 UTC 日期為11月3日,寄出時間為16:42、17:58、20:34、21:07與23:08 PST),取自發現檔,附上決定每一筆的細節:全部都是 resumegeni.com 或 blakecrosley.com 上的 WAF 洪泛,含有沒有記錄到封鎖或質詢的事件;11月1日的六筆,edge 封鎖或質詢的非機器人事件數(發現中的 acted 計數)低於事件數(83中的5、153中的95、104中的0、128中的67、135中的54、108中的80);11月2日有兩筆完全沒有封鎖(05:55 PST,26次質詢;12:06 PST,204次質詢);對全部20筆,監控程式的日誌顯示沒有任何單一位址的事件數足以觸發封鎖;第6節表格中的兩列(2026-11-02T00:51:04Z 與 06:45:59Z);把每一個非機器人防火牆事件都算作「WAF block」的摘要文字;16:51那一陣有104個非機器人事件、共117個事件,沒有任何一個被封鎖或質詢;以及日誌顯示於11月1日太平洋時間00:30至13:32之間寄出的五筆嚴重警報,發現中的封鎖與質詢計數(79個事件中0與0、81個中0與9、89個中1與0、84個中1與9、76個中0與5);發現沒有記錄那些事件帶有什麼動作。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  14. 作者的程式碼與資料,2026年11月3日:監控程式的 WAF 洪泛摘要範本,當天早上先改寫為 N WAF events in 5 minutes: B blocked, C challenged, U through,其中 N 為非機器人計數;在這篇文章的審查之後,再改為對每一個取樣事件計算的 N WAF events in 5 minutes: B blocked, C challenged, U unmitigated (S from non-bot user agents),JavaScript 質詢算作已質詢;其自動封鎖原因 N WAF events from this address in 5 min;在自動封鎖執行之前寫在嚴重警報上的「pending」處置結果,摘要會把它印成一次在警報路徑完成前被切斷的執行;封鎖清單併入條件的位址集合(該發現自身的位址,以及符合自動封鎖資格的位址)及其位於 WAF 併入條件之前的順序;自動封鎖的重複檢查,在此之前以網站為單位運作,因此把11月2日的位址寫入清單兩次,當天改為以位址為單位(該版本的監控程式設計筆記,以及11月3日的營運日誌);摘要的執行健康狀況規則(記錄到的執行次數、執行之間的中位分鐘數、最長的間隔及其時間,只有超過20分鐘的間隔才在主旨中標記);以及當天早上的預覽,寫著「about one every 5.6 min」與「RUN GAP 31 min at 05:56」。 ↩↩↩↩↩↩↩↩↩↩↩

  15. 作者的資料:本機掃描器2026年11月1日的日誌:10:03:04針對 Apple 的 spotlightknowledged、CPU 74.9%的嚴重發現,以及10:03:06的「Critical email sent」那一行;當天較早的兩筆嚴重警報(00:48:55,路徑 shim),各自接著一次失敗的寄送;以及10月31日日誌的14筆嚴重警報,其中包括22:52:57的 AI 蠕蟲模式,以及22:41的五筆「Claude hook modified」(Claude hook 已被修改)發現,其中四筆接著一次失敗的寄送(如10月31日營運日誌所記,那些 hook 是在10月24日修改的)。 ↩↩↩↩

  16. 作者的資料:11月2日摘要寄出後摘要程式的狀態紀錄:主旨「Mon Nov 2: 71 blocks on 15 zones, 11 criticals emailed, RUNS SHORT 162/207,」,時間窗2026-11-01T21:48:49Z 至2026-11-02T15:05:17Z,162次執行;監控程式的日誌記錄寄送時間為07:05:19 PST。 ↩↩

  17. 作者的資料:以腳本對監控程式2026年11月1日與2日日誌所做的執行間隔分析。11月2日摘要的時間窗(1,036.5分鐘,207個五分鐘時段):165次執行開始,其中4次在下一次開始前沒有「run complete」(執行完成);160個一般間隔,中位數5.60分鐘,平均5.79,最小5.35,合計926.0分鐘(185個時段);4個超過10分鐘的間隔,共103.0分鐘。11月2日這個日曆日(午夜到午夜,1,440分鐘,288個五分鐘時段):242次開始,比時段數少46,沒有任何一次未完成;239個一般間隔,中位數5.62分鐘,合計1,374.7分鐘(約275個時段);2個超過10分鐘的間隔,共35.8分鐘。拆分是根據這些數字的近似算術:約25.2個執行節奏時段(160個一般間隔橫跨185.2個五分鐘時段,容納160次執行),三個睡眠間隔中約15.6個時段(93.0分鐘,18.6個時段,三次執行),14:19那次執行之後10.0分鐘的間隔中約1.0個時段,以及3次未記錄的執行,合計約45。 ↩↩↩↩↩↩↩↩↩

  18. 作者的資料:監控程式的設定歷史,讀自其儲存庫:10月31日22:44 PDT 啟用(每筆嚴重警報與每個工作階段結束各一封電子郵件);11月1日00:46 PDT(嚴重警報併入封鎖郵件);11月1日13:50 PST(07:00啟用摘要、關閉逐筆封鎖郵件、併入 edge 已處理的嚴重警報);11月1日14:00 PST(設定未變;WAF 併入條件的程式碼改為計算每一個事件並要求完整樣本)。 ↩↩↩↩↩↩↩

  19. 作者的營運日誌(Captain’s Log),2026年10月31日:本機掃描器的寄送因 Cloudflare 針對 Python 預設使用者代理的錯誤1010而失敗,並以一把錯誤的金鑰重現;當晚14筆嚴重警報對應13次失敗寄送的計數;雲端郵件「most likely were」送達。 ↩↩↩↩

  20. Resend,“Event Types,”,webhook 文件,擷取時間14:23:37Z:email.sent 的定義,引文;以及作為另一個事件的 email.delivered。 ↩↩↩↩

  21. Resend,“Send Email,”,API 參考文件,擷取時間14:18:59Z:回應主體是一個 id。 ↩

  22. 作者的資料:2026年11月1日依當地小時,取自同一支腳本,01:00這個小時依 PDT 與 PST 分開:每小時的電子郵件數(午夜那個小時22封,全部未經驗證)、每小時併入或抑制的警報數、13:25:57的最後一封逐筆封鎖郵件,以及14:20:35第一則併入的逐筆封鎖通知。 ↩↩↩↩

  23. Cloudflare,“Querying Firewall Events with GraphQL,”,Analytics 文件,擷取時間14:19:01Z:查詢的欄位,包括 action,以及含有 "log" 與 "block" 的範例輸出;該頁沒有列出所有的 action 值。 ↩↩

  24. Cloudflare,“Security Events,”,WAF 文件,擷取時間14:23:10Z:安全事件的定義、單一請求可能產生多個事件的那一句,以及關於取樣的那一句,引文。 ↩↩↩

  25. 作者的本機掃描器設計筆記,「Check fixes and false positives」(檢查修正與誤報):「most of the CRITICALs it raised in its first live days were its own noise,」、誤報表格(Homebrew Python、Xcode、作者的 App 建置、事件監聽的自我比對、版本管理器 shim、比對到另一個專案代理程式指示的 AI 蠕蟲模式),以及程式碼簽章那一條,引文;掃描器自行寄出它的嚴重警報。 ↩↩↩↩↩

  26. Cloudflare,“Cloudflare Alerts,”,Notifications 文件,擷取時間14:19:00Z:警報的兩個類別,引文;Monitors 是排程執行的 SQL API 查詢,Platform Notifications 是預先設定的產品警報,兩者都從儀表板建立,所有方案皆可透過電子郵件遞送。 ↩↩

  27. Ewaschuk,“Monitoring Distributed Systems,”,擷取時間14:18:54Z:關於呼叫太頻繁的段落,引文。 ↩↩

  28. Ewaschuk,“Monitoring Distributed Systems,”,擷取時間14:18:54Z:一個團隊分流警報的案例研究,以及指向心臟監測警報管理的第24號註腳,「for an example of alert fatigue in another context,」,引文。 ↩↩

  29. Rob Ewaschuk,“My Philosophy on Alerting,”,Google 文件,讀自其 HTML 匯出,擷取時間14:18:55Z:文件中說明其想法構成 SRE 書該章節基礎的註記、「Pages should be urgent, important, actionable, and real,」,以及以原因為基礎的警報那一段及其小節標題,引文。 ↩↩↩

  30. Ewaschuk,“My Philosophy on Alerting,”,擷取時間14:18:55Z:每日報告的段落、其問責的但書,以及要求指定一個人每天分流報告的呼籲,引文。 ↩↩↩↩↩↩

  31. Steven Thurgood,與 Jess Frame、Anthony Lenton、Carmela Quinito、Anton Tolchanov 及 Nejc Trdin 合著,“Alerting on SLOs,”,The Site Reliability Workbook(Google,O’Reilly Media)第5章,擷取時間14:18:55Z:精確率、召回率與重置時間的定義,引文。 ↩↩

  32. NIST,SP 800-61 Revision 2, Computer Security Incident Handling Guide(2012年,已被取代),擷取時間14:18:58Z:「thousands or even millions」(數千甚至數百萬)那一句,引文。 ↩

  33. NIST,SP 800-61 Revision 3(2025年4月),擷取時間14:18:57Z:其取代 r2 的聲明,以及 Adverse Event Analysis(不利事件分析)下的建議 R1,引文。 ↩

  34. Vectra AI,“2023 State of Threat Detection”(廠商調查;2023年3月至4月,由 Vectra 委託,Sapio Research 執行實地調查,對象為十個市場中員工超過1,000人之組織的2,000名資安分析師),擷取時間14:22:49Z:每天4,484則警報與67%被忽略,依受訪者自述。 ↩↩

  35. 作者的程式碼:摘要程式的說明(「One email a day … in place of an email per auto-block and per WAF-handled CRITICAL」;「The digest is also the heartbeat: it goes out on a quiet day too」;監控程式在2026年稍早長達數月的停擺期),以及截至11月2日,其以時間窗分鐘數除以五計算預期執行次數的規則。 ↩↩↩↩↩↩↩↩↩

  36. Cloudflare,“Actions reference,”,Ruleset Engine 文件,擷取時間14:19:01Z:block、質詢、skip 與 log 動作,質詢與 log 的定義,引文;以及 skip 與 log 被列為非終止動作。 ↩↩↩↩

  37. 作者的資料:依記錄的處置結果與類別統計的嚴重發現,取自監控程式的發現檔,依 UTC 日期。11月1日:129筆,其中118筆沒有處置結果:117筆產生於開始記錄處置結果之前(其中包括本機掃描器的行程、hook 與供應鏈類別,這些從來不帶處置結果),以及一筆14:13 PST 的雲端掃描器嚴重警報,在變更之後,其所屬執行的最後一行日誌是它觸發的自動封鎖(監控程式11月1日的日誌)。11月2日:236筆(160筆因位址已被封鎖而併入、1筆因 WAF 已處理而併入、58筆被抑制、14筆已寄信、3筆本機的沒有處置結果)。 ↩↩

  38. 作者的資料:監控程式2026年11月1日的日誌:三次執行(開始於14:09:49、14:19:46與23:10:31)的最後幾行落在開始後約四分鐘,沒有記錄任何看門狗、逾時或終止行,作者將其解讀為監控程式的240秒看門狗(程式碼會在240秒時終止一次執行);以及一次在14:36:06開始、在14:36:34結束卻沒有「run complete」的執行。 ↩↩

  39. 作者的重播,2026年11月3日,以監控程式自己的表單洪泛檢查,對11月2日18:58:23至19:03:23 UTC(10:58:23至11:03:23 PST)的完整 Cloudflare 資料執行,產生了即時執行漏掉的發現,嚴重程度為 high(監控程式會把它送進摘要,而不是電子郵件或封鎖清單),依據為39次送出、其中23次被拒絕,並計得該位址的請求為2,143個,而即時執行計得1,914個;當天從監控程式程式碼中讀出的兩個原因(每次執行的時間窗結束於偵測器發出查詢的那一刻,早於 Cloudflare 最新資料完全抵達;而在相隔超過五分鐘才開始的執行上往回看五分鐘,讓每個間隔都有一部分未被掃描),以及當天所做的修正(即時時間窗依據上一個時間窗結束處的紀錄銜接,並提早90秒結束;紀錄不存在、不到60秒,或超過15分鐘時,退回往回看五分鐘;重播從不讀取該紀錄),以修改後的程式碼重播同一個時間窗得到相同的發現,這顯示該變更沒有影響固定時間窗上的偵測,但並未驗證時間窗銜接或延遲;掃描器對聯絡表單的送出,記錄於作者11月2日的營運日誌。以11月3日程式碼所做的重播,連同本文其餘證據一併保存:其確切指令、讀取的時間窗,以及偵測器對執行時間窗與表單時段18:58至19:05 UTC 的完整輸出,於11月3日15:55:04 UTC 執行。第一次重播是11月3日稍早以修正前的程式碼所做,記錄在我的專案筆記中,計數相同;其原始輸出未保存。 ↩↩↩↩↩

  40. 作者的資料:本機掃描器2026年11月2日的日誌,以及11月3日的摘要預覽:13:50 PST 的三筆嚴重「Browser -> shell chain」發現,一個 shell 啟動了 curl,在發現檔中尚未解決。 ↩↩

  41. 作者的資料:發現檔中11月1日 spotlightknowledged 發現所記錄的解決說明,引文。 ↩

  42. Cloudflare,“Error 1010,”,支援文件,擷取時間14:19:00Z:該錯誤的定義與 Python urllib 的例子,引文;該頁的這個例子是針對發往 *.pages.dev 與 *.workers.dev 主機名稱及 Pages 自訂網域的請求。 ↩

  43. 作者的營運日誌(Captain’s Log),2026年11月2日:RUNS SHORT 那一行,引文。 ↩

  44. 作者的資料:Mac 的電源日誌(自11月1日13:40 PST 起的 Sleep 與 Wake 行):23:21:30閒置睡眠、00:30:05完全喚醒;06:01:20閒置睡眠、06:30:28完全喚醒。 ↩

相關文章

AI 代理程式可觀測性:如何監控看不見的東西

AI 代理程式在維運人員毫無可見性的情況下消耗磁碟、CPU 與網路。三層可觀測性能在損害無法挽回之前補上這道缺口。

22 分鐘閱讀

深夜時分

午夜至凌晨6點之間,Googlebot 爬取21,000個頁面,Bingbot 爬取10,000個,綜合檢查則掃過15,000個頁面。這個網站在凌晨3點比下午3點更加活躍。

6 分鐘閱讀

Ralph 迴圈:我如何在夜間運行自主 AI 代理

我建構了一套自主代理系統,搭配停止鉤子、生成預算與檔案系統記憶體。以下是失敗經驗與真正能交付程式碼的方法。

9 分鐘閱讀