一個 HTTP 請求從攻擊者的瀏覽器出發,到被保護網站回應為止,依序經過哪些站、每一站看到的「來源 IP」是誰、哪一站有能力把它擋下來。

圖中的攻擊者位址 203.0.113.42 不是真實 IP:203.0.113.0/24 是 RFC 5737 保留給文件範例用的 TEST-NET-3,不會出現在 Internet 路由上。安裝包的 --test-event 送的測試事件也用這個位址,而平台的保護清單刻意不把它列為受保護網段,正是為了讓端對端驗證能拿它當「公網攻擊者」走完整圈。
Cloudflare 是建議的對外方式,本架構完整支援。安裝包內含 cloudflared 服務(compose profile tunnel)與 cf_tunnel.py(用 Cloudflare API 自動建 tunnel、ingress 與 DNS),安裝時給 --cf-api-token 與 --cf-hostname 就完成;沒有網域時也可以在 Zero Trust 後台手動建 tunnel。不用 Cloudflare 也能運作,第二節的內網直打路徑就是,差別只在對外入口與攻擊者 IP 的歸因來源。

被 WAF 擋下的請求,Suricata 看不到。403 在第 4 站就回頭了,永遠不會走到第 5 站的實體網卡。所以「同一次 SQL injection 同時有 WAF 事件與 Suricata 事件」只在 WAF 放行時才可能發生。反過來,Suricata 對第 5 站看到的是「WAF 已經放行的請求」,它抓到的東西通常是 CRS 沒涵蓋的型態(掃描器指紋、惡意 User-Agent、特定 CVE 特徵)或後端回應中的異常。
沒有網域或還沒接 Cloudflare 時,從內網直接打 http://<主機 B>:8080 也會經過 WAF。路徑短很多,但多了兩件事:nftables 的來源管制,以及 Suricata 會看到兩次。
nftables 是主機 B 最外層,但它有兩個 hook,管的對象不同。這件事決定了「封鎖清單到底擋得住什麼」,第 5 篇會再回來談。
docker 的 nat / filter 表由 docker 自己管,安裝包刻意只重建 inet secstack 一張表、不 flush 整個 ruleset,否則會打斷所有 port forwarding。重建表會清空 blocklist,所以腳本會先把現有元素(含剩餘 timeout)記下來再補回去。
