WordPress 主機被掃描攻擊怎麼辦?fail2ban 不是萬靈丹,你需要的是四層防禦

一台 1 vCPU 的 WordPress 主機被掃描洪流打到 CPU 100%。從查源頭、邊緣止血,到 Nginx 限流、壞路徑斷線、fail2ban 自動化的四層防禦實戰,並破解『裝個 fail2ban 就一勞永逸』的常見誤解。

發布2026.06.10 最後更新2026.06.15 閱讀時間11 分鐘
資料中心機房的伺服器機櫃
本文目錄
  1. 01一張監控圖,CPU 貼著 100%
  2. 02先搞清楚:誰在打、打的是什麼
  3. 03為什麼「掃不存在的檔」就能把伺服器打趴?
  4. 04第一步:止血——在「最外圈」把 IP 封掉
  5. 05治本:把防禦做成「四層」
  6. 06重點來了:「裝了 fail2ban 就一勞永逸」是錯的
  7. 07正確的心法:分層,而不是迷信單一工具
  8. 08結語

一張監控圖,CPU 貼著 100%

那天晚上,我打開雲端監控儀表板,看到自家網站主機的 CPU 使用率整條貼在 100%,系統負載(Load Average)一度衝破 8。

機房中藍光照明的伺服器刀鋒
多層防禦在流量抵達 WordPress 之前先層層過濾,降低被掃描與攻擊打中的機會。

先把這兩個數字翻成白話:這台機器只有 1 顆 CPU 核心(規格上叫「1 vCPU」),而 Load Average 可以粗略想成「現在有幾件工作在排隊等 CPU 處理」。一顆核心,健康狀態下這個數字應該在 1 以下;衝到 8,等於「一個人的櫃台前面排了八組客人在咆哮」,機器已經忙到喘不過氣。後端開始噴出大量 503 錯誤——503 的意思是「伺服器暫時無法服務」,白話講就是處理請求的工人全被占光了,新客人連門都進不去,包含正常的訪客。

被攻擊了。但我做的第一件事不是「封」,而是「查」。搞不清楚對手是誰就亂封,很容易誤傷 Google 的爬蟲或雲端的健康檢查,結果攻擊沒擋到,反而把自己的搜尋排名和服務搞壞。

先搞清楚:誰在打、打的是什麼

我的診斷很制式:先看整體負載趨勢,再列出「誰在吃 CPU」(果然是一排處理 PHP 的工人程序),接著把 Nginx 的存取紀錄(access log,也就是「每一個來訪請求的流水帳」)撈出最近幾千行來分析。

技術上,我用文字處理指令統計每個來源 IP 出現幾次,並且把 IP 聚合成 /24 網段再排名。/24 是什麼?你可以把它想成「同一條街的門牌」——1.2.3.x 開頭、後面 0 到 255 的這 256 個 IP 算同一條街。為什麼要看整條街?因為有些攻擊者會在同一條街裡輪流換門牌,用「每個 IP 只打幾下」來規避「單一 IP 被限速」的防禦;只看單一 IP 會被它騙過,看整條街才抓得出來。

結果很清楚,兩個 IP 包辦了將近 4000 次請求:

  • 第一個來自某家國外雲主機商的伺服器(沒有反向網域名稱,這本身就可疑),狂掃 /db.zip/db.tar.gz/db.sql/db.war……一整排檔名。這是典型的「資料庫備份掃描器」——它在賭你有沒有不小心把整個資料庫的備份檔(裡面是你全站的資料)丟在網站根目錄忘了刪。它每次請求都換一個假的瀏覽器識別字串(User-Agent,就是瀏覽器自報「我是誰」的那串資訊),一下假裝 Chrome、一下假裝 Safari,目的就是讓你以為是不同人,難以一眼識破是同一隻機器人
  • 第二個更貪心,專掃 /.env/.env.local/wp-config.php.save.1/.ftpconfig/smtp.json……這些是「密鑰與設定檔掃描」。這些檔案平常藏著你的資料庫密碼、寄信帳號、各種 API 金鑰。.envwp-config.php 是正規的設定檔,而 .save.bak.1 這種結尾,通常是有人手動改檔時編輯器自動留下的備份——攻擊者很清楚這個壞習慣,專挑這些「備份檔」下手,因為它們往往沒被權限保護到。這個 IP 正是把後端打到噴 503 的元兇。

兩者有個共同特徵:它們打的全是「不存在的檔案」,回應碼不是 404(找不到)就是 499(它自己提早把連線掐掉了)。它們不是來看你的內容,而是來「翻你垃圾桶找鑰匙」,順便用海量請求把你的 CPU 燒乾。

為什麼「掃不存在的檔」就能把伺服器打趴?

這是最反直覺的一點:既然檔案不存在,回個「找不到」不是很便宜嗎?

問題在於 WordPress 的「找不到」一點都不便宜。 技術上講,當一個請求打進來、Nginx 發現沒有對應的實體檔案,它會把球丟給 PHP,於是 WordPress 開始「完整開機」:載入核心程式、跑一輪所有外掛、初始化佈景主題、向資料庫查詢好幾次……全部跑完,才總算得出結論「喔,這個網址不存在,回 404 吧」。

用白話打個比方:這就像有人按你工廠的門鈴問「請問有賣鳳梨嗎?」,而你的回answer流程是——把整間工廠的電源打開、所有生產線啟動、員工全部就位、查完整本庫存清單,然後才走到門口跟他說「抱歉沒有」。一次這樣就夠累了,何況掃描器是用每秒幾百次的速度在按門鈴。對一台只有一顆核心的機器,這就是壓垮駱駝的稻草。換句話說,一個假的 404 請求,成本幾乎跟正常打開一個頁面一樣重,這正是這類攻擊的陰險之處。

第一步:止血——在「最外圈」把 IP 封掉

確認兩個 IP 都是鐵板釘釘的惡意掃描器之後(判斷依據:全打不存在的檔、不斷換假身分、而且是固定的單一 IP),我把它們加進雲端供應商的防火牆封鎖名單。

這裡有個關鍵抉擇:要在哪一層封? 我選擇在雲端的「網路邊緣」封,而不是在主機裡面封。差別很大——

技術上,邊緣防火牆會在封包還沒抵達你的主機之前,就在雲端供應商的骨幹網路把它丟掉。白話說,這就像在整個社區的大門口就把壞人攔下,他根本走不到你家門前;你家的人力(CPU)完全不用出動。這層防護還有一個救命的特性:就算主機已經被打到連遠端登入(SSH)都擠不進去,你還是能從雲端控制台動手封鎖,因為這道牆根本不在那台快當機的主機上。

封完,負載應聲回落。止血成功。

但這裡要講一句重話:封 IP 不是解決方案,只是 OK 繃。 攻擊者明天換一個 IP,你今天的封鎖就完全失效;而你不可能 24 小時盯著流水帳手動追 IP。所以真正的課題是:怎麼讓系統自動、而且在「對的層級」擋下這類攻擊?

治本:把防禦做成「四層」

我替這台主機建立了四道縱深防線,每一層擋不同的東西、在不同時機生效:

第一層|雲端邊緣防火牆(最外圈、最省力)。 對付「已知且持續」的惡意 IP,在社區大門口就丟包,主機完全不耗資源。缺點是名單要人工或自動維護。

第二層|Nginx 即時限流(最關鍵)。 技術上,我設定每個 IP「每秒最多 40 個請求,瞬間可容許爆量到 80 個」,超過就回 429(意思是「你太快了,請慢一點」)。這層的價值在於「即時、零延遲」——白話說,就是在你家門口站一個警衛,請求一進門當下就判斷該不該放行,洪流根本到不了裡面那台昂貴的 PHP 處理機。這才是真正保護一顆 CPU 不被燒乾的核心。

這層有兩個魔鬼藏在細節裡,做不好反而會傷到自己。其一,我把真正的靜態資源(圖片、CSS 樣式、JS 腳本、字型)排除在限流之外——因為一個圖多的頁面,瀏覽器會在一瞬間同時抓幾十個檔,如果不排除,會被自己的限流誤判成攻擊,把正常頁面打到圖裂、版面壞掉。其二,我放行了雲端健康檢查與主機自己的內部網段,避免限流誤殺自家的基礎設施。所以限流不是把數字調低就好,真正的功夫是「懂得該放誰過」。

第二·五層|壞路徑直接斷線。 對於 .env/.gitdb.zipwp-config.php.save 這種一看就知道是來找麻煩的網址,我讓 Nginx 直接回 444444 是個特殊代碼,意思是「話都不說,直接把連線掛斷」。關鍵在於:這麼做根本不會驚動 WordPress 去開機。回到剛才的比喻——對於明顯來鬧的人,警衛看一眼就把門甩上,完全不用啟動後面那整間工廠,省下的 CPU 非常可觀。

第三層|fail2ban 自動化。 技術上,它會持續讀 Nginx 的流水帳,發現「某個 IP 一直觸發限流、或一分鐘內狂收幾十個 444」,就自動把它丟進防火牆封一段時間。白話說,它是一個會自己看監視器、自己抄壞人車牌去封鎖的保全系統。它的價值是「自動化」——讓我不必再像事件當晚那樣熬夜手動追 IP。

四層疊起來,才是一套完整的防禦。而這,正好帶出本文最想糾正的一個迷思。

重點來了:「裝了 fail2ban 就一勞永逸」是錯的

網路上一堆文章,談到主機被掃描、被暴力破解,結論幾乎都是一句:「裝個 fail2ban 就好啦。」彷彿裝上去就從此天下太平。

這個觀念半對半錯,而且很危險。 fail2ban 是好工具,但如果你把它當成一面萬能盾牌、以為裝了就高枕無憂,下一次攻擊你還是會被打趴。原因有三個:

第一,它是「事後反應」,天生有時間差。 技術上,fail2ban 的邏輯是「先在流水帳上看到某 IP 犯規 N 次,才出手封鎖」。但這次的攻擊是幾秒內幾千發的閃電洪流——很可能整波都打完了、CPU 都燒過一輪了,fail2ban 的封鎖才剛要生效。白話說,它像個要先看到對方鬧夠 N 次才會動手的保全;對方如果是「閃電戰、打了就跑」,等保全反應過來,客廳早被翻完了。它真正擅長的,是對付「連續好幾分鐘不停試密碼」那種持續性攻擊,而不是瞬間爆量。

第二,它在「主機裡面」封,不是在大門口封。 技術上,fail2ban 是透過主機自己的防火牆(iptables / nftables)來封鎖,這代表封包已經抵達你的主機、連線已經被處理過一輪,它才把後續擋掉。白話說,這是「人都已經走到你家門口、按了門鈴,你才把門關上」;而前面講的雲端邊緣防火牆,是「在社區大門口就攔住,他連你家門口都到不了」。對一台一顆 CPU 的小機器,光是處理這些已經進門的連線,本身就是負擔。兩者完全是不同量級的防護。

第三,它對「輪流換 IP」幾乎無解。 現在很多攻擊來自殭屍網路或代理池,攻擊者一個 IP 打幾下就換下一個。fail2ban 一個一個 IP 去封,永遠追不完;等你封到第 100 個,他第 101 個又上了。

所以真相是:fail2ban 的定位是「自動化的善後工具」,不是「擋下攻擊的主力」。 真正在第一時間擋住 CPU 被燒乾的,是第二層的即時限流第二·五層的壞路徑斷線——這兩層是「即時的、在請求進到昂貴的 PHP 之前就處理掉」。fail2ban 是疊在它們上面的自動化,負責把「一直來鬧、被限流多次」的慣犯,從「每次都擋一下」升級成「乾脆整個封掉」。

把因果擺對很重要:不是「裝了 fail2ban 所以安全」,而是「先有即時限流與早期拒絕擋住主力,fail2ban 再來收尾」。 只裝 fail2ban、卻沒有限流和壞路徑拒絕,等於只請了打掃阿姨,卻沒裝門鎖——客廳早就被翻過一輪,阿姨才慢慢來掃地。

正確的心法:分層,而不是迷信單一工具

回頭看,這次事件給我的提醒不是「該裝哪個神器」,而是安全要做成「縱深」:

  • 越靠近最外圈(雲端防火牆)的防護,成本越低、效果越強,但名單要維護;
  • 越靠近最裡面(WordPress 外掛)的防護,越精準但越花資源;
  • 而中間那層「即時限流 + 早期拒絕壞路徑」,才是性價比最高、最該優先建立的核心地基。

fail2ban 在這套體系裡有它的位置,但它是錦上添花,不是地基。任何把單一工具講成「一勞永逸」的說法,都值得你多問一句:它在哪一層生效?它有沒有時間差?攻擊者換個手法,它還擋得住嗎?

結語

那天晚上的攻擊,從發現到止血大約十幾分鐘。但真正有價值的不是「封了兩個 IP」,而是趁這個機會,把臨時的 OK 繃換成了一套會自己運作的縱深防線。下一次再有掃描器上門,系統大多會自動限流、自動斷線、自動封鎖,我甚至不需要醒著。

如果你也在自己管理 WordPress 主機,有兩句話想送你:別等被打趴了才開始想防禦,也別以為裝一個 fail2ban 就能交差。先把「即時限流」和「壞路徑拒絕」做好,再讓 fail2ban 去自動收尾——這個順序,才是真的把門鎖上。


本文以實際維運事件改寫,文中已隱去主機內部位址與白名單等敏感設定。如果你的網站也常被掃描洪流困擾,歡迎交流。

網站遇到問題,不確定該從哪裡開始?

你可以先告訴我們網站目前的狀況,我們會協助確認適合的處理方向。

緊急救援