快速連結
災情描述與環境設定
近期管理的 Linode 主機(環境為 Ubuntu 20.04 + CyberPanel + OpenLiteSpeed)突然發出警報。透過監控面板與 SSH 的 top 指令發現:
- Load Average (系統負載) 飆高至 15~20 以上。
- Swap (虛擬記憶體) 2.5GB 瞬間被塞滿,導致嚴重的 I/O 卡頓。
- CPU 佔用率 居高不下,主要兇手皆為
lsphp(LiteSpeed PHP 行程) 與mariadbd(資料庫)。
這是一次典型的「快取穿透 (Cache Bypass)」加上「惡意機器人掃描」導致的資源耗盡事件。以下是我們抽絲剝繭、逐步擊破效能殺手的完整紀錄。
第一步:主機急救
當 Swap 被塞滿時,系統會在硬碟與記憶體間不斷搬移資料 (Thrashing),此時重啟網頁伺服器也沒用。我們必須先手動釋放資源,讓主機恢復神智:
清空並重置虛擬記憶體 (Swap)
sudo swapoff -a && sudo swapon -a強制重置 PHP 行程
killall -9 lsphp第二步:抓出內部元凶
透過 strace -p [PID] 與分析 Access Log,我們發現有大量真實訪客的流量繞過了 LiteSpeed 快取,直接喚醒 PHP 進行繁重運算。
兇手 1:行銷追蹤參數 (fbclid, utm_) Facebook 廣告帶來的訪客,網址後方會夾帶 ?fbclid=...。快取系統預設會將帶有參數的網址視為新頁面而不給快取。
- 解法: 進入 LiteSpeed Cache 外掛 -> [快取] -> [忽略查詢字串 (Drop Query String)],加入
fbclid,utm_source,utm_medium等常用參數。
兇手 2:Elementor 與 WooCommerce 的購物車 AJAX (Cart Fragments) Elementor 的購物車圖示為了隨時保持最新數量,會在訪客進站時發送 admin-ajax.php 請求(行為:elementor_menu_cart_fragments)。在 WooCommerce 中,針對 admin-ajax.php 的請求是絕對不會被快取的。
- 解法: 安裝並啟用 Disable Cart Fragments 類型的外掛,在購物車為空時阻擋此 AJAX 請求,瞬間省下極大 CPU 資源。
第三步:抓出外部兇手
內部問題解決後,CPU 再次無預警飆高。我們進一步追查日誌,抓到了真正的效能吸血鬼。
兇手 3:備份外掛 (UpdraftPlus) 排程撞車 主機上多個網站的 UpdraftPlus 備份排程同時在白天尖峰時段啟動,檔案壓縮與上傳過程產生了龐大的 I/O 負載,直接塞爆 Swap。
- 解法: 將所有網站的備份排程移至半夜(如凌晨 3 點),並將不同網站的備份時間錯開。
兇手 4:惡意爬蟲狂刷「加入購物車」與「動態搜尋」 從 Access Log 中發現,中國搜狗爬蟲 (Sogou web spider) 無視 robots.txt,瘋狂模擬點擊 ?add-to-cart= 連結;同時有未知機器人狂刷 FiboSearch 的動態搜尋網址 (?s=...&dgwt_wcas=1)。這些動作會強迫伺服器建立 Session 並向資料庫進行複雜查詢。
- 解法: 單靠伺服器阻擋已經來不及,必須將防線推至 Cloudflare WAF。
第四部:Cloudflare WAF 規則設定
為了徹底阻斷惡意掃描,我們在 Cloudflare (免費版) 中設定了以下 4 條精簡且強大的 WAF 規則 (Custom Rules):
WordPress 核心與敏感檔案防護
阻擋不該被存取的設定檔,並防止核心目錄中被惡意執行 PHP 木馬。
- Action: Block
- Expression:
(http.request.uri.path in {"/xmlrpc.php" "/readme.html" "/wp-config.php"}) or (http.request.uri.path contains ".git") or (http.request.uri.path contains ".env") or (http.request.uri.path contains ".htaccess") or (http.request.uri.path contains "debug.log") or (starts_with(http.request.uri.path, "/wp-content/") and ends_with(http.request.uri.path, ".php")) or (starts_with(http.request.uri.path, "/wp-includes/") and ends_with(http.request.uri.path, ".php"))後台登入區域限制 (僅限台灣)
防禦暴力破解最有效的方法,限制只有台灣 IP 能訪問後台。
- Action: Block
- Expression:
(starts_with(http.request.uri.path, "/wp-admin") and not http.request.uri.path contains "admin-ajax.php" and ip.src.country ne "TW") or (http.request.uri.path eq "/wp-login.php" and ip.src.country ne "TW")惡意爬蟲與效能殺手防護
阻擋常見的無頭腳本,並針對會造成快取失效的查詢參數 (add-to-cart, dgwt_wcas) 進行質詢。
- Action: Managed Challenge
- Expression:
(http.user_agent contains "curl") or (http.user_agent contains "wget") or (http.user_agent contains "python") or (http.user_agent contains "scrapy") or (http.user_agent contains "libwww") or (http.user_agent contains "Go-http-client") or (http.user_agent eq "") or (http.request.uri.query contains "add-to-cart" and not http.referer contains "網站網址") or (http.request.uri.query contains "dgwt_wcas" and not http.referer contains "網站網址")底層漏洞攻擊防護 (SQLi / XSS / LFI)
防止駭客利用 URL 參數進行惡意指令碼注入。
- Action: Block
- Expression:
(http.request.uri.path contains "%c0") or (http.request.uri.query contains "../") or (http.request.uri.query contains "/etc/passwd") or (http.request.uri.query contains "win.ini") or (http.request.uri.query contains "wget ") or (http.request.uri.query contains "curl ") or (http.request.uri.query contains "cat /") or (http.request.uri.query contains "uname ") or (http.request.uri.query contains "union select") or (http.request.uri.query contains "UNION SELECT") or (http.request.uri.query contains "extractvalue") or (http.request.uri.query contains "concat") or (http.request.uri.query contains "<script>") or (http.request.uri.query contains "onload=") or (http.request.uri.query contains "<svg")目前在解決這些問題後,主機CPU有明顯下降