在 Web 伺服器上實作 AI 主動防火牆的故事

在 Web 伺服器上實作 AI 主動防火牆的故事

3 min read

2026.04 / Tech Blog / BASTION

在 Web 伺服器上實裝 AI 主動式防火牆 #

我們建置了一套系統,由本機端 LLM 分析 Fail2Ban 固定門檻值無法偵測到的未知 Bot 模式與垃圾請求,每 15 分鐘自動封鎖一次。我們在既有的 nginx + Fail2Ban 架構上新增了 AI 分析層,建立起 3 層式的防禦結構。

Fail2Ban 雖然優秀,但對「未知」威脅較弱 #

nginx UA 對應 + 速率限制 + Fail2Ban 的組合,是 Web 伺服器 Bot 防護的標準做法。針對一小時內每分鐘產生 10 次 403 錯誤的 IP 進行封鎖。既簡單又可靠。

然而,這種做法存在結構性的弱點。

Fail2Ban 的門檻值是「固定的」。它只會在「每分鐘 403 錯誤 10 次」這類靜態條件下觸發。一邊變更 User-Agent 一邊緩慢爬取的 Bot、鎖定回傳 200 而非 403 的路徑的垃圾請求,以及偽裝成合法瀏覽器 User-Agent 的高頻存取,全都能躲過 Fail2Ban 的門檻值。人類手動檢視存取日誌時能立即察覺可疑的模式,固定規則卻無法捕捉到。

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 的差異 #

Fail2BanBASTION
判斷方式固定門檻值(「每分鐘 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 伺服器區段的報告。

incoming-webhook 07:15

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 次

自動執行封鎖 #

incoming-webhook 00:53

🛡️ 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 資安監控的服務。

BASTION 服務頁面
聯絡我們

Updated on 2026年6月9日

What are your feelings

  • Happy
  • Normal
  • Sad

©2020 BESTNET.LLC . All Rights Reserved.