iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
自我挑戰組

一鍵完成六套開源防禦系統整合系列 第 10 篇

白名單不是一份 IP 清單:四種語意、一個不對稱

  • 分享至 

  • xImage
  •  

第九天講完黑名單 EDL 之後留下一個問題:EDL 執行點吃「放行」決策,nftables 與 CrowdSec 執行點卻不吃,為什麼?要回答它,得先把「白名單」這個字拆開。網管工程師心裡的白名單是一份 IP 清單,命中就免檢查、永久有效、優先於一切。這套架構裡符合這個定義的只有兩處,其餘的「白名單」各自在回答不同的問題。把問題分清楚,那個不對稱就不是例外,而是必然。

先講結論。這套架構裡的「白名單」在回答四個不同的問題:誰能連進來(存取管制)、誰永遠不會被封(免封)、誰說的來源 IP 算數(信任)、對某個來源明確放行(放行決策)。前三種是安裝或管理時設定的固定清單;第四種是案件流程的輸出,帶 TTL,而且只落地到 EDL。它只落 EDL 不是漏做,是因為「放行」的意義是壓過其他封鎖來源,而防禦節點自己只有一個封鎖來源,沒有東西需要被壓過。

一、先拆掉這個字:IP 清單視角漏掉了什麼

用 IP 清單的視角看白名單,只有一個維度:IP 在不在名單裡。但一份清單真正的行為由四個問題決定,而這四個問題在不同的清單上答案完全不同:

問題 IP 清單視角的預設答案 這套架構裡的實際答案
命中之後發生什麼? 免檢查 有的是「能連上這個埠」、有的是「它送的標頭被採信」、有的是「這筆封鎖寫不進去」、有的是「設備上的 deny 規則對它無效」。沒有一個是「免檢查」,WAF 對所有請求照樣打分數
誰寫進去的? 管理員手動 有的是安裝腳本從 .env 產生、有的是平台管理頁、有的是案件流程自動寫入。三者的變更頻率差了三個數量級
多久有效? 永久 固定清單永久;放行決策帶 TTL,到期自動消失
與封鎖清單撞到時誰贏? 白名單贏 視位置而定。主機 B 上 allowlist 排在 blocklist 前面所以贏;EDL 兩份清單同時含同一個 IP 時,誰贏由抓清單的那台設備的規則順序決定,od-bridge 不替它決定

總覽第三節已列出八個放行點並標了類型。本篇不重列那張表,而是把其中「以 IP 為單位」的六個依上面四個問題重新分組,再回答不對稱的成因。

二、四種語意各落在鏈上哪裡

https://ithelp.ithome.com.tw/upload/images/20260924/20184261kzrgRacLaT.png

A 存取管制:誰能連進來

三處都是同一種東西:一個埠或一個帳號只接受名單內的來源。主機 B 上兩處由同一份 ADMIN_IPS 產生(nftables 的 ingest_guard_、mgmt_guard_、ssh_guard_input 各 chain,加上 ClickHouse 帳號的 networks);主機 A 上的平台端 EDL 端點 /edl//blocklist.txt 用 OD_EDL_ALLOWED_IPS 限來源。這是最接近網管直覺的白名單,但它與安全決策無關:命中只代表 TCP 連得上,之後該過的檢查一樣過。第 6 篇說設備 IP 不在 ADMIN_IPS 內抓 EDL 會逾時,就是這一類。

B 免封:誰永遠不會被封

方向與 A 相反。A 管「誰能進」,B 管「誰不能被踢出去」。兩處:

機制 內容 在哪一步生效
主機 B nftables allowlist set 平台主機 IP(由 BEAK_BASE_URL 自動補入)與 ADMIN_IPS,安裝時由 nftables.sh 寫死,flags interval、無 timeout input chain 第一條 ip saddr @allowlist accept,排在 blocklist drop 之前。就算平台誤發一筆封鎖管理機的決策,od-bridge 照寫進 blocklist,kernel 也先 accept 了。這是「自鎖保險」:od-bridge 不寫這個 set,它只在 /state/nft 頁面把它讀出來給人看
主機 A 平台端禁封清單(od_protected_targets) 出廠 16 條(RFC1918、回送、link-local、CGNAT、群播、保留段、IPv6 ULA 與 link-local)+平台 .env 的 TRUSTED_PROXY_IPS 與 OD_PROTECTED_EXTRA_NETWORKS+企業自訂的 protect 項目;另可加 exempt 項目讓落在保護網段內的特定主機可封 DecisionWriter 寫 block 之前比對,命中即拒寫。只檢查 block,allow 與 unblock 不比對。在平台端做一次,防禦端不帶本地副本

兩者都是「否決封鎖」,但層次不同:禁封清單在決策產生前擋掉(那筆決策根本不存在,任何執行點都收不到);自鎖保險在決策落地後讓它無效(決策存在、也寫進 set 了,只是 kernel 先放行)。前者是政策,後者是保險絲。

C 信任:誰說的來源 IP 算數

反向代理架構下,攻擊者 IP 不是封包來源,是標頭裡寫的值。TRUSTED_INGRESS_LIST(主機 B 的 Vector)與 TRUSTED_PROXY_IPS(主機 A 的平台)回答的是「哪些直連者送來的 CF-Connecting-IP 或 XFF 可以當真」。名單內的來源不是免檢,它自己的請求照樣過 WAF;差別只在它宣稱的「真正的來源」被採信,其餘直連者一律「誰打的記誰」。詳細在第 5 篇第一節。把這一類當成 IP 白名單去擴充,後果是讓那個 IP 可以陷害任何第三方。

D 放行決策:對某個來源明確放行

只有這一種是動態的。案件流程裡的 DecisionWriter 節點寫一筆 action=allow 的決策(平台合法的動作有五種:block、unblock、allow、escalate、observe),帶 ttl_seconds,od-bridge 拉回來後由 edl enforcer 寫進 allowlist.txt,經 :8500/edl/allow 給邊界設備抓。它的用途是「這個來源被判定為誤判或合作對象,在邊界上請放行,有效期若干小時」。與 A、B、C 三種固定清單相比,它會過期、由流程而非人手產生、而且只有一條落地路徑。下一節解釋為什麼。

三、那個不對稱:為什麼 allow 只落 EDL

三個 enforcer 對五種動作的支援,是 2026-09-13 逐檔對照原始碼確認的(decision_writer_handler.py 的 ENFORCEMENT_POINT_ACTIONS 表就是依此寫的,註解要求「不得憑印象增修」):

執行點 block unblock allow 落地方式
nftables 支援 支援 unsupported_action nft add element 進 blocklist(帶 timeout)/delete element。不碰 allowlist set
CrowdSec 支援 支援 unsupported_action LAPI POST /v1/decisions type=ban(帶 duration)/DELETE
EDL 支援 支援 支援 reconciler 重繪 blocklist.txt/allowlist.txt,unblock 從兩份移除
Cloudflare — — — 整支尚未實作,任何動作回 not_implemented_yet

不支援不是還沒做,是那個位置不需要「放行」這個動作。關鍵在一句話:

「放行」的意義是壓過其他封鎖來源。一個位置有幾個封鎖來源,決定了它需不需要獨立的放行清單。
位置|那裡有幾個封鎖來源|所以
:--|:--|:--
主機 B 的 nftables|一個:od-bridge 自己寫的 blocklist。沒有別的東西會往這個 set 加元素|要讓某個 IP 不被擋,把它從 blocklist 拿掉就完成了,那就是 unblock。再加一份可動態寫入的 allow set 不會多任何能力,反而多一個風險:流程的一筆決策就能把任意 IP 提升為「input chain 第一條 accept」,與自鎖保險混在一起,管理機與平台 IP 這種安裝時就該固定的清單從此可以被流程改寫
CrowdSec|一個由 API 管的:LAPI decisions。CrowdSec 的 whitelist 是 parser 層的設定檔(出廠只含 127.0.0.1),不是 LAPI 能動態寫的物件;LAPI 決策只有 ban、captcha 這類懲罰型別,沒有「allow」型別|放行同樣等於 unblock(刪 decision)。要動態 allow 得改設定檔並重載 agent,那不是執行點該做的事
邊界設備|很多:設備自帶的威脅情資、GeoIP 規則、其他來源的 EDL、人工寫的 deny 規則,加上我們這份 blocklist|一筆「這是誤判,請放行」若只做 unblock,只能移除我們自己那份清單裡的項目,設備其他來源的封鎖照樣擋。只有把它寫進一份獨立的 allow 清單、放在所有 deny 規則之上,才壓得過。這就是 allow 動作存在的唯一理由,也是它只在 EDL 有意義的理由

實作上的配套:DecisionWriter 在寫決策之前就依 ENFORCEMENT_POINT_ACTIONS 過濾,allow 配到 nftables 或 crowdsec 會被剔除並留一筆 warning(dropped_enforcement_points),一個都不剩時預設補 ['edl']。若沒有這層過濾,od-bridge 拉到手回 unsupported_action,整筆決策會從 applied 掉成 failed,處置中心看到的是「放行失敗」,而實際上是配錯執行點。這是 2026-09-13 的裁示,此前 SOC 流程範本裡的放行節點就是這樣失敗的。

四、allow 與 unblock:另一個常混的地方

網管視角裡「放行」和「解封」是同一件事,這套裡是兩個動作,行為差在三處:

面向 unblock(解封) allow(放行)
語意 取消我們自己下過的封鎖。「停止對這個目標採取行動」 宣告這個來源應被放行,即使其他來源封了它也一樣
能否先於封鎖存在 不行。沒封過就 unblock,od-bridge 回 already_absent,視為成功但什麼都沒發生 可以。可以預防性地放行一個從未被封的合作對象 IP,等日後誤判時已經在名單上
對 od-bridge EDL 兩份清單的影響 從 blocklist.txt 與 allowlist.txt 兩份都移除 加進 allowlist.txt,不動 blocklist.txt。同一個 IP 可以同時在兩份清單上,誰贏由設備的規則順序決定
對主機 A 平台端 EDL(PF-154)的影響 兩者都算 override:計算黑名單時,決策時間晚於該目標 block 的 override 會把那筆 block 排除。平台端 EDL 只出黑名單、沒有 allowlist,所以 allow 在這裡的效果與 unblock 相同,且只對「較早的」封鎖有效;之後又來一筆新的 block,會重新出現 同左
禁封清單比對 不比對 不比對(禁封清單只檢查 block)
執行點 nftables、CrowdSec、EDL 都吃 只有 EDL

兩套 EDL 對同一個 IP 的答案可能不同。主機 B 的 od-bridge EDL 是「兩份清單各自獨立,由設備決定優先序」;主機 A 的平台端 EDL 是「先算好結果,只給一份黑名單」。若邊界設備抓的是平台端那份,allow 之後又有新的 block 進來,該 IP 會重新出現在黑名單上;抓 od-bridge 那份的設備則因 allow 規則在上而繼續放行。要接哪一份,先想清楚你要的是哪種語意。

五、翻譯表:「我想把 X 加白名單」其實是想要哪一種

這張表是給拿到這套系統的網管工程師用的。左欄是常見的需求說法,中欄是它其實在問四種語意的哪一種,右欄是去哪設。

需求 語意 去哪設
辦公室對外 IP 不管怎樣都不能被封 B 免封 平台管理頁「開放防禦 → 封鎖保護清單」加一筆 protect。在決策產生前就擋掉,所有執行點一起生效,不必動主機 B
管理機要能開 Grafana、EveBox、8500 的頁面 A 存取管制 主機 B .env 的 ADMIN_IPS 加 IP,跑 install.sh --reconfigure。順帶也進了自鎖保險(B)與 ClickHouse 帳號限制(A)
怕平台誤判把主機 B 自己或平台主機鎖死 B 免封 不用設。安裝時 nftables.sh 已把平台 IP 與 ADMIN_IPS 寫進 allowlist set
某個客戶 IP 被邊界防火牆擋了,要放行一段時間 D 放行決策 在案件流程裡走放行(DecisionWriter action=allow,帶 TTL),落到 :8500/edl/allow;設備上要有以它為來源、排在 deny 之上的 allow 規則。若只是我們自己封錯了,用 unblock 就夠
WAF 對某支 API 一直誤判 403 不是 IP 白名單 總覽第三節第 8 條:modsecurity-override.conf 的規則排除,依路徑移除特定規則的檢查目標。不要用 IP 去解 WAF 誤判,那會讓那個 IP 的所有請求都免檢
前面新加了一台反向代理,要讓它送的 XFF 被當真實來源 C 信任 主機 B .env 的 TRUSTED_INGRESS_EXTRA;平台側是 TRUSTED_PROXY_IPS。加之前確認那台代理不會被第三方直連,否則等於開了一個陷害別人的入口
另一套監控系統要往 8500 送事件 A 存取管制+授權 ADMIN_IPS 讓它連得上 8500,BRIDGE_INGEST_TOKEN 讓它有權送;平台側再看 API Key 的 source_systems scope(總覽第三節第 6 條,那是系統名稱不是 IP)
把內網某台測試機排除在禁封之外,讓它可以被封來做演練 B 免封的例外 封鎖保護清單加一筆 exempt,目標必須完全落在某條 protect 網段內。豁免一台不會讓整段變成可封

六、三個「白名單不是免檢」

命中了什麼 仍然會發生的檢查
ADMIN_IPS(A) 只代表連得上管理埠與 8500。它對被保護網站發的請求照樣過 WAF 打分數、照樣被 Suricata 看、照樣可能因為攻擊行為觸發案件。它不會被封只是因為同時也在自鎖保險(B)裡,而那只救主機 B 的 input
TRUSTED_INGRESS_LIST(C) 它自己的請求照樣檢查。被採信的只是它宣稱的「真正來源」,這反而讓被歸因的第三方承擔後果
EDL allow 清單(D) 只在抓了它的那台邊界設備上生效。WAF 不讀 EDL,主機 B 的 nftables 不讀 EDL,CrowdSec 不讀 EDL。一個在 allow 清單上的 IP 送惡意請求,WAF 一樣 403、一樣產生事件、一樣可能再被判 block;到時它會同時在兩份清單上,誰贏看設備

七、常見誤解

誤解 實際
白名單就是一份清單,加進去就什麼都不擋 這套有四種語意、六處以 IP 為單位的清單,沒有任何一處是「什麼都不擋」。要先問「我想要它免於哪一道檢查」,再決定加哪一份
nftables 執行點不支援 allow 是功能缺口 主機 B 上只有一個封鎖來源,放行等於解封,unblock 已涵蓋。加了反而讓流程能改寫安裝時固定的自鎖保險
allow 決策落地失敗,是 od-bridge 壞了 先看決策的 enforcement_points。2026-09-13 之後 DecisionWriter 會自動剔除不支援的執行點,之前建的流程範本若寫死 nftables 就會這樣失敗
allow 之後這個 IP 就從黑名單消失了 od-bridge 的 EDL 不會。allow 只加進 allowlist.txt,blocklist.txt 原樣;要它從黑名單消失用 unblock
把辦公室 IP 加進 ADMIN_IPS 就永遠不會被封 只有主機 B 的 input 這一段不會。邊界設備抓的 EDL 黑名單、CrowdSec bouncer、平台端 EDL 都不看 ADMIN_IPS。要全面免封,設的是平台的封鎖保護清單
CrowdSec 有 whitelist,所以可以動態放行 那是 parser 層設定檔,出廠只有本機回送位址,改了要重載 agent。od-bridge 不寫它,LAPI 也沒有 allow 型別的決策

上一篇
EDL 黑名單:從哪來、放在哪、誰該吃它
下一篇
nftables 在防禦節點上的角色:一張表、三個集合、四種責任
系列文
一鍵完成六套開源防禦系統整合 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言