SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-30

UFW IPv6 漏洞:VPS 防火牆缺口怎麼補

UFW 與雲端防火牆可能只限制 IPv4,讓 VPS 服務透過公開 IPv6 直接暴露。了解 Ubuntu 24.04 的成因、檢查方式與修補方法。

一句話說明 IPv6 防火牆陷阱

您的防火牆保護 IPv4。您的 VPS 幾乎一定也有公開 IPv6 位址,而且許多服務預設會在該位址上監聽。如果防火牆只涵蓋 IPv4,或您依賴只過濾 IPv4 的雲端防火牆,那麼這些服務全都能透過 IPv6 從整個網際網路連入,即使 IPv4 端看起來已受到嚴格限制。您使用 curl 測試連接埠,看到連線遭拒,便以為環境安全。攻擊者則透過 IPv6 連線到相同的連接埠,直接進入系統。

本指南說明在一般 Ubuntu 24.04 VPS 上,這個缺口從何而來、如何確切查看您暴露了哪些服務,以及如何關閉這個缺口。UFW 不是問題所在。在現代 Ubuntu 安裝環境中,UFW 已能處理 IPv6。暴露問題來自周邊的各個層,以及您不知道正在監聽的服務。

VPS 為什麼一開始就使用 IPv6

現在幾乎每台 VPS 都會提供公開 IPv6 位址,通常還有一整個 /64,並與 IPv4 位址並存。請檢查你的 VPS:

ip -6 addr show scope global
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet6 2001:db8:2a::1/64 scope global

這個 2001:db8:2a::1 可從網際網路上的任何位置路由到,和你的 IPv4 位址完全相同。現在查看正在監聽的服務:

sudo ss -tlnp
State   Recv-Q  Local Address:Port   Process
LISTEN  0       0.0.0.0:22           sshd
LISTEN  0       [::]:22              sshd
LISTEN  0       127.0.0.1:5432       postgres
LISTEN  0       [::]:8080            docker-proxy

仔細查看 Local Address 欄位。0.0.0.0:22 表示「在所有 IPv4 位址上監聽」。[::]:22 表示「在所有 IPv6 位址上監聽」。127.0.0.1:5432 綁定至 loopback,完全不會公開,因此 Postgres 那一列是安全的。兩列 [::] 會透過 IPv6 回應整個網際網路,而 docker-proxy 則是你可能忘記曾經啟動的服務。

大多數 daemon 預設會綁定至 ::,因為在 Linux 上,:: socket 通常也能接受 IPv4 連線。因此,新伺服器的預設狀態是「在兩種網路協定堆疊的所有位址上回應」。防火牆是唯一位於這些服務之前的防線,所以防火牆只處理其中一種協定堆疊,就會造成實際問題。

IPv6 漏洞實際上從何而來

常見來源有 4 種。在特定伺服器上,可能只有其中 1 種,也可能同時存在數種。

1. 僅篩選 IPv4 的雲端防火牆。 許多供應商防火牆與 security group 產品是以 IPv4 為基礎發展而來,因此可能忽略 IPv6,或需要另外手動新增 IPv6 規則。如果唯一使用的防火牆是供應商控制面板中的防火牆,且未涵蓋 IPv6,則無論 IPv4 的 port 22 顯示何種設定,您的 [::] 服務都會直接暴露在外。請閱讀供應商的防火牆文件,並特別搜尋 IPv6。

2. 手動撰寫 iptables,但未設定 ip6tables。 iptables 指令只會處理 IPv4 tables。IPv6 使用完全分開的指令 ip6tables,並有自己獨立的規則。如果您撰寫了包含許多 iptables -A INPUT ... 行的防火牆 script,卻從未撰寫相對應的 ip6tables 規則,IPv6 防火牆就是空的。INPUT chain 的預設 ACCEPT policy 若未設定規則,就會允許所有流量:

sudo ip6tables -L INPUT -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

這份輸出完整呈現了問題。IPv4 受到篩選,IPv6 卻接受所有來源。

3. Docker 直接繞過防火牆發布 port。 執行 docker run -p 8080:80 時,Docker 會在 UFW 的規則之前插入自己的規則。因此,即使 ufw status 顯示該 port 被拒絕,已發布的 port 仍可被連線;在現代 Docker 中,IPv6 也適用相同情況。Docker 為何會繞過 UFW,以及如何正確篩選 container port 說明其運作機制與修正方法。如需了解這些已發布 port 如何宣告,請參閱 VPS 上的 Docker Compose 基礎

4. 關閉 IPv6 的 UFW。 UFW 支援 IPv6,但必須先啟用相關設定。請檢查此開關:

grep IPV6 /etc/default/ufw

現代 Ubuntu 會提供 IPV6=yes,因此 UFW 會將每條規則同時套用至兩個 protocol stack。如果看到 IPV6=no,表示映像檔或指南版本較舊。您撰寫的所有 UFW 規則都只套用至 IPv4,而 IPv6 未受到管理。

確切查看對外暴露的項目

不要猜測。從外部實際測量。先列出監聽中的連接埠,並記下每個繫結至 :: 的連接埠:

sudo ss -tlnp | grep '::'

接著從另一台機器連線至伺服器的公開 IPv6 位址,並測試一個你認為已關閉的連接埠:

curl -6 -v http://[2001:db8:2a::1]:8080/

如果回傳頁面或 banner,表示該連接埠已在 IPv6 上開放。關閉的連接埠會回傳 Connection refused 或逾時。這兩種失敗代表的訊號不同,而 拒絕連線與逾時的差異 能告訴你主機是否已回應並拒絕連線,或是防火牆靜默丟棄了封包。若要取得完整結果,請從伺服器外部使用 nmap 掃描該 IPv6 位址:

nmap -6 2001:db8:2a::1

nmap 回報在 IPv6 上開放的每個連接埠,都是整個網際網路可以連線的連接埠,無論你的 IPv4 掃描結果為何。將 IPv4 與 IPv6 掃描結果並排比較,是找出差異最快的方法:任何在 -6 上開放、但在 IPv4 上關閉的連接埠,都是防火牆遺漏的服務。

縮小防護缺口

讓 UFW 同時涵蓋 IPv4 與 IPv6,並將預設政策設為拒絕。 確認切換狀態,然後設定預設拒絕輸入流量的政策,只允許必要的流量:

sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

如果啟用 IPV6=yes 時 UFW 已經在執行,必須執行 sudo ufw reload,變更才會生效。

ufw status 會將每條規則列出 2 次,一次是一般規則,另一次則帶有 (v6) 後綴。看到 (v6) 行時,表示 UFW 正在過濾 IPv6:

22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)

如果手動管理 iptables,請在 ip6tables 中鏡像設定每條規則,或改用 nftables。nftables 的 inet 表可在同一處涵蓋 IPv4 與 IPv6,避免這類錯誤。自行撰寫規則時,使用單一 nftables inet filter table 是最乾淨的修正方式。如果 VPS 執行的是 Rocky 或 AlmaLinux,而不是 Ubuntu,便沒有 UFW 可供設定;改由 firewalld 作為管理介面,其 zone 規則會同時套用至兩種協定堆疊。

將不應公開的服務繫結至 loopback。 資料庫、管理面板或 metrics endpoint 通常完全不需要公開位址。將服務繫結至 127.0.0.1::1,讓它一開始就不會監聽可路由的位址。對 Postgres,設定 listen_addresses = 'localhost'。對應用程式伺服器,將其繫結至 127.0.0.1,並在前方放置反向代理。關閉 listener 比設定防火牆更可靠,因為這樣便沒有可供連線的服務。

不要依賴 UFW 保護 Docker 發布的連接埠。 將容器連接埠發布至特定位址,而不是所有介面,例如 -p 127.0.0.1:8080:80,讓該連接埠只能由主機及你明確設定的代理存取。容器確實需要公開時,請放在 Traefik 反向代理 後方,只發布代理的連接埠,不要逐一發布每個應用程式的連接埠。

在供應商防火牆中加入 IPv6 規則,否則就必須接受它不是 IPv6 的防火牆,改由主機上的 UFW 或 nftables 負責。

確認連接埠確實已關閉

完成變更後,再次執行相同的外部測試:

curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1

先前有回應的連接埠現在應拒絕連線或逾時,而 nmap 應回報該連接埠為 filtered 或 closed。如果連接埠仍然開啟,請重新檢查上述 4 個來源:服務仍繫結至 ::,但前方沒有任何規則;Docker 規則優先於 UFW;或服務提供者的防火牆根本未處理 IPv6。

完全不讓敏感服務暴露在公用網際網路上,安全性更高。將 SSH 與管理面板放在 WireGuard VPN 後方,並封鎖這些服務的連接埠,使其只在通道上回應,如此便不必再處理 IPv6 暴露問題。若要降低針對仍公開服務的暴力破解掃描速度,可在預設拒絕的防火牆上,再於 SSH 前方加入 Fail2ban

如果你還不熟悉連接埠,請先閱讀 什麼是連接埠,以及服務如何監聽連接埠

FAQ

UFW 預設會封鎖 IPv6 嗎?

在現代的 Ubuntu 24.04 安裝中,會。UFW 會從 /etc/default/ufw 讀取 IPV6=yes,並將每條規則套用到 IPv4 和 IPv6;ufw status 會以 (v6) 後綴顯示 IPv6 規則。常見問題是 IPV6=no(來自舊映像檔或舊教學),或依賴只篩選 IPv4 的供應商防火牆,也可能是 Docker 將連接埠發布到 UFW 之外。使用 grep IPV6 /etc/default/ufw 檢查此設定。

如何檢查 VPS 在 IPv6 上公開了哪些項目?

執行 sudo ss -tlnp,並注意每個本機位址以 [::] 開頭的監聽項目;這表示該項目會在所有 IPv6 介面上接受連線。接著從另一台機器直接使用 curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/ 測試伺服器的公開 IPv6 位址,或使用 nmap -6 YOUR:IPV6::ADDR 掃描該位址。IPv6 掃描顯示開放、但 IPv4 顯示關閉的連接埠,就是需要處理的缺口。

為什麼 UFW 顯示 Docker 容器的連接埠已封鎖,我仍然可以連線?

使用 -p 發布連接埠時,Docker 會將自己的防火牆規則插入 UFW 規則之前。因此,即使 ufw status 將該連接埠列為拒絕,發布的連接埠仍可連線。IPv4 會發生此情況;啟用 Docker 的 IPv6 支援時,IPv6 也會發生。將發布位址限制為特定位址,例如 -p 127.0.0.1:8080:80;或將容器置於反向代理後方,只發布反向代理的連接埠。

如果我的 IPv4 防火牆設定完善,仍然需要 IPv6 防火牆嗎?

需要。IPv4 和 IPv6 是不同的網路堆疊,並使用不同的防火牆規則。完善的 IPv4 規則對 IPv6 流量不會產生任何作用。如果 VPS 具有公開 IPv6 位址,而幾乎所有 VPS 都是如此,任何監聽 :: 的服務都會持續透過 IPv6 提供連線,直到 IPv6 防火牆規則或繫結至 loopback 位址的設定阻止它。

如何讓服務只監聽 IPv4,或只監聽 localhost?

在服務本身的設定中指定繫結位址。繫結至 127.0.0.1 可只使用 IPv4 loopback,繫結至 0.0.0.0 則可使用所有 IPv4 位址且不監聽 IPv6。Postgres 使用 listen_addresses,SSH 使用 ListenAddress,大多數應用程式伺服器則提供 host 或 bind 旗標。使用 sudo ss -tlnp 確認結果,並檢查 Local Address 是否不再顯示 [::]