WordPress 網站被攻擊?讓 Fail2Ban 來救援!
如果您曾經負責做 WordPress 網站,您大概知道當有人決定用垃圾流量塞滿您的伺服器時有多麻煩。像 Cloudflare 這樣的服務雖然很有幫助,且免費方案允許加入速率限制(Rate limiting)規則,但不是每一個網站都可以掛在 Cloudflare。因此,對於那些沒有使用 Cloudflare 的網站,您需要在自己的伺服器上安裝防火牆,而 Fail2Ban 就是一個簡單且效果不錯的的工具。
運作邏輯如下:首先,Nginx 會監控每秒請求數的激增情況。我們會排除 CSS、JS 和media的圖片。接著,任何超過限制的請求都會在 Nginx 的 Access Log 中被記錄為 429 錯誤。Fail2Ban 隨後會掃描這些log尋找特定模式,並封鎖濫用的IP。
設定 Nginx
首先,我們需要建立一個新的速率限制規則,這可以透過把這個程式碼加入 server block 中來完成:
geo $limit_bypass {
default 0;
# 任何您想要排除的 IP
# 我通常會把像 Google 或 Ahrefs 這樣的「好」crawler放在這裡
}
map $request_uri $limited {
default $binary_remote_addr;
~^/wp-content/ "";
~^/wp-includes/ "";
~^/wp-admin/ "";
~^/wp-json/ "";
}
map $limit_bypass:$limited $final_limit_key {
~^1: "";
default $limited;
}
limit_req_zone $final_limit_key zone=one:10m rate=3r/s
上面的程式碼會將 wp-admin、wp-json、wp-content 和 wp-includes 排除在速率限制之外,因為這endpoint包含靜態資源、media 和 AJAX 請求。此外,封鎖 wp-json 或 wp-admin 可能會導致 WP-Admin 後台或某些外掛出現問題。
接著,在您的 server block 中的某個位置,您必須加我們建立的規則:
location / {
index index.php index.html;
try_files $uri $uri/ /index.php?$args;
# 套用速率限制規則:
limit_req zone=one burst=3 nodelay;
limit_req_status 429;
}
在 Fail2Ban 中設定 Jail
首先,如果您還沒安裝 Fail2Ban,請先安裝。在 Ubuntu/Debian 中,可以透過 apt 安裝:
sudo apt install fail2ban
就像我前面提到的,Fail2Ban 的運作方式是監控access log並封鎖符合特定模式的 IP。我們先從建立自己的規則開始,複製預設設定檔:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
現在開啟 .local 檔案並定義您的規則,如下所示:
[nginx-req-limit]
ignoreip = <任何您想排除的 IP>
enabled = true
filter = nginx-custom-filter
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 3600
bantime = 7200
port = http,https
這些數字要看您的需求來決定,因為每個網站的流量都不一樣。概念很簡單:如果一個 IP 訪問您網站的次數超過了我們在 Nginx 中定義的限制,它將被封鎖兩小時(7200 秒)。您可以將其修改得更嚴格或更輕鬆。
儲存檔案後,在 /etc/fail2ban/filter.d/nginx-custom-filter.conf 建立filter:
[Definition]
failregex = ^<HOST> - 429 -
ignoreregex =
如您所見,為了讓它正常運作,我們的access log必須符合特定格式。在下一步中,我們將調整 Nginx 的access log格式。
儲存檔案後,重新啟動 Fail2Ban:
sudo service fail2ban restart
檢查 Jail 是否啟用:
sudo fail2ban-client status
調整 Nginx access log格式
Nginx 的預設格式並非我們所需的,因此我們必須建立一個客製化的access log格式。
要使用自定客製化的access log格式,請在 access_log 指令的末尾加上格式名稱(可以是任何名稱),如下所示:
access_log /var/log/nginx/access.log custom
接著,在您的 nginx.conf 中加 access log 格式(需要在 http 區塊內):
log_format custom '$remote_addr - $status - $remote_user [$time_local] '
'"$request" $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
重新啟動 Nginx:
sudo nginx -s reload
現在 Fail2Ban 將會監控access log,並對access log中出現的任何 “429” 回應代碼做出反應。
測試設定
您可以使用一個簡單的bash script,透過重複請求您的伺服器:
for i in {1..200}; do curl -s https://example.com >/dev/null; done
然後檢查 Fail2Ban:
sudo fail2ban-client status nginx-http
您應該會看到您的 IP 出現在封鎖名單上。然後你使者在瀏覽器上打開你的網站,應該會失敗(通常會一直轉圈圈)。
如何用 Cloudflare 設定Rate Limiting
您也可以透過前往 Security(安全性) → Security Rules(安全性規則) → Rate Limiting Rules(速率限制規則) 在 Cloudflare 中建立類似的邏輯。建立一個新規則並輸入此程式碼:
(not starts_with(http.request.uri.path, "/wp-content/") and not starts_with(http.request.uri.path, "/wp-includes/") and not starts_with(http.request.uri.path, "/wp-json/") and not starts_with(http.request.uri.path, "/wp-admin/"))
接著將速率限制設定為每 10 秒 8–10 個請求(時間只能設定為 10 秒)。
對於動作(Action),選擇「Block(封鎖)」——— 請注意,持續時間也只能設定為 10 秒。
Cloudflare 的選項限制較多,但即使是免費方案也提供速率限制功能,如果您不想在自己的伺服器上進行手動設定,這是一個不錯的替代工具。