UFW 與 IPv6 防火牆設定教學:如何修補 VPS 的 IPv6 安全漏洞
檢查您的 VPS 是否因僅設定 IPv4 的 UFW 或雲端防火牆而導致 IPv6 暴露。本文針對 Ubuntu 24.04 提供實作指南,教您如何檢查 netstat 監聽狀態並確保 ip6tables 與 UFW 正確攔截所有 IPv6 流量,避免服務被外部攻擊者入侵。
一句話說明 IPv6 防火牆陷阱
您的防火牆保護了 IPv4。您的 VPS 幾乎肯定也擁有公用 IPv6 位址,且許多服務預設會在該位址進行監聽。如果您的防火牆僅涵蓋 IPv4,或者您依賴僅過濾 IPv4 的雲端防火牆,那麼當您的 IPv4 端看起來已封鎖時,所有這些服務都能透過 IPv6 從整個網路存取。您使用 curl 測試連接埠,看到連線被拒絕,便感到安心。然而,攻擊者可以透過 IPv6 連接到同一個連接埠並入侵。
本指南說明在標準 Ubuntu 24.04 VPS 上,此漏洞是如何產生的、如何精確查看您所暴露的內容,以及如何修補它。UFW 並非問題所在。在現代 Ubuntu 安裝中,UFW 已能處理 IPv6。風險來自於 UFW 周邊的層級,以及您並未察覺正在監聽的服務。
為什麼您的 VPS 預設使用 IPv6
現今幾乎所有的 VPS 在提供 IPv4 位址的同時,也會附帶一個公用 IPv6 位址,通常還包含整個 /64。請檢查您的設定:
ip -6 addr show scope global2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
inet6 2001:db8:2a::1/64 scope global該 2001:db8:2a::1 與您的 IPv4 位址一樣,可以從網際網路任何地方進行路由。接著查看目前正在監聽的服務:
sudo ss -tlnpState 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 則是您可能在啟動後就忘記的類型。
大多數守護行程 (daemons) 在預設情況下會綁定至 ::,因為在 Linux 上,:: socket 通常也會接受 IPv4。因此,新伺服器的預設狀態是「在所有位置的兩種協定棧上進行回應」。防火牆是唯一的防線,這就是為什麼若防火牆僅能偵測單一協定棧會造成嚴重的問題。
IPv6 漏洞的實際成因
常見原因有四種。在特定主機上,可能同時存在其中一個或多個問題。
1. 僅過濾 IPv4 的雲端防火牆。 許多供應商的防火牆與 security-group 產品是針對 IPv4 設計的,因此會忽略 IPv6,或者需要手動新增獨立的 IPv6 規則。如果你的防火牆僅限於供應商控制台中的設定,且該設定未涵蓋 IPv6,那麼無論 IPv4 的 port 22 設定為何,你的 [::] 服務都會處於開放狀態。請閱讀供應商的防火牆文件,並特別尋找 IPv6 字樣。
2. 使用 iptables 但未設定 ip6tables。 iptables 指令僅會更動 IPv4 表格。IPv6 使用完全獨立的指令 ip6tables,並擁有各自的規則。如果你撰寫的防火牆腳本中全是 iptables -A INPUT ... 行,卻未撰寫對應的 ip6tables 規則,則你的 IPv6 防火牆將是空的;而一個預設策略為 ACCEPT 的空 INPUT chain 會允許所有連線:
sudo ip6tables -L INPUT -nChain INPUT (policy ACCEPT)
target prot opt source destination上述輸出結果即是陷阱所在。IPv4 已受過濾,但 IPv6 卻對全世界開放。
3. Docker 直接跳過防火牆發布連接埠。 當你執行 docker run -p 8080:80 時,Docker 會在 UFW 之前插入自身的規則,因此即使 ufw status 顯示該連接埠已被拒絕,已發布的連接埠仍可被存取;在現代 Docker 中,此情況同樣適用於 IPv6。為什麼 Docker 會繞過 UFW,以及如何正確過濾容器連接埠 解釋了其機制與修復方法。關於如何宣告這些發布的連接埠,請參閱 VPS 上的 Docker Compose 基礎知識。
4. UFW 已關閉 IPv6 功能。 UFW 確實支援 IPv6,但前提是必須啟用。請檢查此開關:
grep IPV6 /etc/default/ufw現代 Ubuntu 預設搭載 IPV6=yes,因此 UFW 會將規則同時套用於兩個協定棧。如果你從舊版映像檔或舊版指南中看到 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無論 IPv4 掃描結果為何,只要 nmap 回報該連接埠在 IPv6 上為 open,即代表全球網路皆可存取該連接埠。對照 IPv4 與 IPv6 的掃描結果是找出差異最快的方法:任何在 -6 上為開啟但 IPv4 為關閉的連接埠,皆代表您的防火牆漏掉了該服務。
補足漏洞
讓 UFW 同時涵蓋 IPv4 與 IPv6 堆疊,並預設拒絕所有連線。 確認設定切換後,設定預設拒絕(deny)的入站策略,並僅允許必要的連線:
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 會列出每條規則兩次,一次為原始格式,一次帶有 (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 過濾表是最簡潔的解決方案。
將不需對外公開的服務綁定至 loopback。 資料庫、管理介面或指標端點(metrics endpoint)通常不需要公開位址。將其綁定至 127.0.0.1 與 ::1,使其從根本上不會監聽可路由的位址。對於 Postgres,請設定 listen_addresses = 'localhost'。對於應用程式伺服器,請綁定至 127.0.0.1 並在前端配置反向代理。關閉監聽比使用防火牆更有效,因為這樣根本沒有目標可以連線。
不要依賴 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。若連接埠仍處於 open 狀態,請依序檢查上述四個來源:服務仍綁定於 :: 且前方缺乏規則、Docker 規則位於 UFW 之前,或是供應商防火牆完全未偵測到 IPv6。
將敏感服務完全移出公網會更安全。將 SSH 與管理介面置於 WireGuard VPN 後方 並對其連接埠進行防火牆設定,使其僅在隧道內回應,如此即可避免 IPv6 暴露問題。若要減緩針對公開服務的暴力破解掃描,請在預設拒絕(default-deny)的防火牆之上,疊加 在 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 container 的連接埠?
當你使用 -p 發布連接埠時,Docker 會在 UFW 之前插入自己的防火牆規則,因此即使 ufw status 將該連接埠列為拒絕,發布的連接埠仍可連線。這發生在 IPv4 上,若 Docker 的 IPv6 支援已開啟,也會發生在 IPv6 上。建議發布至特定位址(例如 -p 127.0.0.1:8080:80),或是將 container 置於反向代理(reverse proxy)後方,並僅發布代理伺服器的連接埠。
如果我的 IPv4 防火牆已設定完善,還需要 IPv6 防火牆嗎?
需要。IPv4 與 IPv6 是獨立的網路協定棧,擁有各自的防火牆規則。完美的 IPv4 規則對 IPv6 流量完全沒有保護作用。如果你的 VPS 擁有公用 IPv6 位址(幾乎所有 VPS 都有),那麼任何監聽於 :: 的服務,在被 IPv6 防火牆規則或 loopback 綁定阻擋前,在 IPv6 上都是可連線的。
如何讓服務僅監聽 IPv4 或僅監聽 localhost?
在服務自身的設定檔中設定綁定位址(bind address)。若僅限 IPv4 loopback,請綁定至 127.0.0.1;若要綁定所有 IPv4 位址且不開啟 IPv6 監聽,請綁定至 0.0.0.0。Postgres 使用 listen_addresses,SSH 使用 ListenAddress,大多數應用程式伺服器則提供 host 或 bind 旗標。請使用 sudo ss -tlnp 確認結果,並檢查 Local Address 是否不再顯示 [::]。