在 Web 伺服器上實裝 AI 主動式防火牆 #
我們建置了一套系統,由本機端 LLM 分析 Fail2Ban 固定門檻值無法偵測到的未知 Bot 模式與垃圾請求,每 15 分鐘自動封鎖一次。我們在既有的 nginx + Fail2Ban 架構上新增了 AI 分析層,建立起 3 層式的防禦結構。
Fail2Ban 雖然優秀,但對「未知」威脅較弱 #
nginx UA 對應 + 速率限制 + Fail2Ban 的組合,是 Web 伺服器 Bot 防護的標準做法。針對一小時內每分鐘產生 10 次 403 錯誤的 IP 進行封鎖。既簡單又可靠。
然而,這種做法存在結構性的弱點。
BASTION 讓本機端 LLM 對這些「人類會察覺、但固定規則抓不到的模式」進行判斷。
3 層式防禦結構 #
我們在既有的 nginx + Fail2Ban 架構上新增了 BASTION 的 AI 分析層,建立起 3 層式結構。
| 層級 | 職責 | 判斷方式 | 應變速度 |
|---|---|---|---|
| 第 1 層 | nginx(UA 對應 / 速率限制 / deny.conf) | 靜態規則 | 即時(逐請求) |
| 第 2 層 | Fail2Ban(與 firewalld 整合) | 固定門檻值(每分鐘 403 錯誤 10 次) | 1 分鐘內 |
| 第 3 層 | BASTION(LLM 分析 → 透過 SSH 操作 firewalld) | LLM 判讀日誌上下文 | 15 分鐘內 |
各層各自獨立運作。若 Fail2Ban 先行封鎖了某個 IP,BASTION 會執行重複檢查以避免重複封鎖。BASTION 的強項在於「偵測未知模式的能力」。
監控項目 #
BASTION 的 Web 伺服器監控範本每 15 分鐘會分析以下 6 大類別。
| 類別 | 資料來源 | 偵測內容 |
|---|---|---|
| HTTP 狀態碼分布 | 存取日誌 | 403/429/5xx 集中的 IP。偏離正常狀態的情形 |
| Bot User-Agent 偵測 | 存取日誌 | 未知 Bot User-Agent × 高頻請求 |
| 垃圾請求 | 存取日誌 | 語言切換洪水等特定參數的垃圾請求 |
| 惡意軟體偵測 | ClamAV 日誌 | 上傳檔案中偵測到病毒 |
| SSH 驗證失敗 | sshd 日誌 | 密碼錯誤 / 無效使用者 |
| 應用程式錯誤 | PHP-FPM 日誌 | FATAL/ERROR 等級 |
封鎖機制 #
為何在 Web 伺服器上封鎖,而不是在 WAN 邊界防火牆 #
BASTION 的被動式防禦通常會在 WAN 邊界防火牆的 API(例如 OPNsense)上封鎖攻擊來源 IP(請參閱前一篇文章)。然而,在 Web 伺服器透過 DNAT 對外公開的架構中,WAN 邊界防火牆的封鎖清單有時無法涵蓋前往該 Web 伺服器的流量。
因此,我們準備了一條獨立的防禦路徑,直接在 Web 伺服器的 firewalld + nginx deny.conf 中設定封鎖規則。
BASTION (Analysis Server) → SSH connection (dedicated service account, public key authentication, minimum privilege sudo) → firewall-cmd drops IP (L3/L4 level) → nginx deny.conf appends IP + reload (L7 level)
SSH 連線安全性 #
從分析伺服器連線到 Web 伺服器的 SSH,使用專用服務帳號,並將 sudo 權限限制在僅必要的指令範圍內。
# sudoers authorized commands (nothing else can execute) svc-monitor ALL=(root) NOPASSWD: /usr/bin/firewall-cmd svc-monitor ALL=(root) NOPASSWD: /usr/sbin/nginx svc-monitor ALL=(root) NOPASSWD: /usr/bin/tee -a /etc/nginx/deny.d/* svc-monitor ALL=(root) NOPASSWD: /usr/bin/sed -i * /etc/nginx/deny.d/*
我們並未使用 root 登入,而是建立了專用服務帳號,採用能通過 ISMS 稽核的最小權限設計。
與 Fail2Ban 的差異 #
| Fail2Ban | BASTION | |
|---|---|---|
| 判斷方式 | 固定門檻值(「每分鐘 403 N 次」) | LLM 讀取日誌上下文並判斷 |
| 未知模式 | 無法偵測(需要更新規則) | 自動偵測日誌中的異常模式 |
| User-Agent 偽裝 | 若無 403 回應則無法偵測 | 依請求頻率 × 路徑 × 時段進行判斷 |
| ClamAV 整合 | 無 | 偵測到 FOUND → 追蹤上傳來源 IP → 封鎖 |
| 通知 | 電子郵件(依賴 MTA) | Slack(即時通知、可互動操作) |
| 解除封鎖 | 依 bantime 固定時間 | 24 小時後自動解除封鎖 + 可從 Slack 即時解除 |
| 稽核 | fail2ban.log | 結構化稽核日誌([HB_BLOCK]/[HB_UNBLOCK] 標籤) |
BASTION 並非取代 Fail2Ban,而是與其共存。Fail2Ban 會在 1 分鐘內偵測並封鎖「403 洪水攻擊」。BASTION 則透過每 15 分鐘的定期 LLM 分析,偵測「明顯不自然、卻不會產生 403 的模式」。由於兩者涵蓋的範圍不同,兩者並行可以減少防護死角。
實際運作情形 #
分析報告 #
透過每 15 分鐘的定期分析,會自動輸出 Web 伺服器區段的報告。
Web 伺服器詳細分析
請求數:1,847
狀態碼:200=1,650 / 403=112 / 429=45 / 5xx=0
403 集中 IP:xxx.xxx.156.12(40 次)— User-Agent:GPTBot/1.0
疑似 Bot 的 User-Agent:「SomeNewBot/2.0」(15 分鐘內 180 次)— 未登記的 User-Agent
ClamAV:無偵測到
SSH 失敗:0 次 / PHP-FPM ERROR:0 次
自動執行封鎖 #
🛡️ Web 伺服器封鎖執行
IP:xx.xxx.156.12
原因:bot_spam
firewalld:已新增封鎖規則
nginx deny:已套用
手動解除封鎖:@OpenClaw-Monitor unblock xx.xxx.156.12
對 ClamAV FOUND 偵測的自動回應 #
當 ClamAV 在上傳的檔案中偵測到惡意軟體時,BASTION 會立即輸出 CRITICAL 判定。ClamAV 本身只會隔離該檔案,但 BASTION 更進一步,從存取日誌中找出上傳來源 IP,並自動以 firewalld 進行封鎖。這是一種雙管齊下的做法:檔案隔離(ClamAV)+ 網路隔離(BASTION)。
nginx deny.conf 採「盡力而為(Best-Effort)」設計 #
我們以 firewalld 封鎖與 nginx deny.conf 設計了雙重防禦,但同時也設計成即使在未設定 nginx deny.conf 目錄的環境中,僅靠 firewalld 也能提供防護。若無法使用 deny.conf,系統會記錄為「已略過(skipped)」,並由 firewalld 單獨繼續運作。日後只要新增 nginx include 設定,nginx deny 便會在不修改程式碼的情況下自動啟用。這種設計可依環境的就緒程度逐步強化防護。
總結 #
我們在 Web 伺服器上新增了 BASTION 的 AI 分析層,建構出 nginx(第 1 層)→ Fail2Ban(第 2 層)→ BASTION(第 3 層)的 3 層式防禦。固定門檻值無法捕捉到的未知 Bot 模式與垃圾請求,由本機端 LLM 每 15 分鐘自動偵測,並立即由 firewalld 封鎖。
SSH 連線使用專用帳號、最小權限 sudo 與公開金鑰驗證。nginx deny.conf 採盡力而為設計,可依環境就緒程度逐步啟用。BASTION 與 Fail2Ban 共存,各自涵蓋不同的防護範圍。
BASTION 是一項能在封閉式環境中實現 AI 資安監控的服務。