Linux Port 與服務監聽:用 ss 查詢
了解 Port 如何將流量分配給 Linux 服務,並用 ss -tlnp 查看監聽中的程式、Port 與 Local Address,分辨僅本機或公開監聽。
實際上,埠是什麼
埠是讓同一台伺服器同時執行多項服務,且不會混淆其網路流量的數字。您的 VPS 只有一個 IP 位址,但可能同時執行 Web 伺服器、SSH 伺服器和資料庫。封包抵達時,作業系統需要知道封包是要傳給哪一項服務。埠號就是答案。HTTPS 流量通常會傳送到埠 443,SSH 則傳送到埠 22。IP 位址會將封包送到您的伺服器;埠則會將封包送到該伺服器上的正確程式。
埠是 16 位元的數字:16 個位元可表示 0 到 65535,而 0 已保留,因此實務上埠的範圍是 1 到 65535。1024 以下的埠稱為「知名」埠,Linux 預設只允許 root(或獲授予 CAP_NET_BIND_SERVICE capability 的程式)開啟這些埠,因此標準服務會使用這個範圍:SSH 使用 22,HTTP 使用 80,HTTPS 使用 443,DNS 使用 53。net.ipv4.ip_unprivileged_port_start sysctl 可調整這個界線,但預設值為 1024。從 1024 起的埠,一般程式都可以使用。
埠分為 TCP 和 UDP 兩種,而其中一種使用的埠號,與另一種使用相同號碼的埠彼此獨立。TCP 是多數服務使用的連線導向通訊協定,例如 SSH、HTTP 和資料庫。UDP 不需要建立連線,常用於 DNS 和部分 VPN。開啟防火牆規則時,通常會指定使用哪一種,例如 22/tcp。
監聽表示程式正在等待連接
需要接收連接的程式會要求核心在某個連接埠上「監聽」。從這一刻起,該連接埠會在電腦上開啟,程式會回應抵達該處的所有連線,但仍受防火牆規則限制。沒有程式監聽的連接埠只會拒絕連線。因此,任何安全性檢查的第一個問題都是:目前有哪些程式在監聽,以及監聽在哪裡。
用來回答這個問題的命令是 ss:
sudo ss -tlnp這些旗標分別表示 TCP(t)、僅顯示監聽中的 socket(l)、使用數字格式顯示連接埠(n,因此會看到 22,而不是 ssh),以及顯示擁有該 socket 的程序(p)。典型結果如下:
State Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:80 nginxProcess 欄會告訴你每個連接埠由哪個程式擁有。你可以藉此找出不小心留下執行中的程式。
Local Address 欄位才是關鍵
請仔細查看每個連接埠前的位址,因為這會決定誰能連到該服務。您會經常看到以下 3 種情況。
0.0.0.0:22 表示監聽這台機器擁有的所有 IPv4 位址,包括公開位址。只要防火牆允許,該服務就能透過 IPv4 從網際網路連線。
[::]:80 對 IPv6 的意義相同:監聽所有 IPv6 位址,包括公開位址。許多程式預設會繫結到此位址,而在 Linux 中,:: socket 通常也會接受 IPv4 連線。
127.0.0.1:5432 表示「只監聽 loopback」。127.0.0.1 是機器用來與自身通訊的位址,在核心的預設設定下,其他位置無法透過路由連到此位址。繫結在此位址的服務只能由同一台伺服器存取,無法從網際網路連線,即使防火牆允許該連接埠也一樣。因此,上方的 Postgres 項目預設是安全的。例外情況是名為 route_localnet 的核心設定:它預設為關閉,但某些工具會將其開啟,例如 Kubernetes 的 kube-proxy。若此設定開啟,且搭配正確的路由或 NAT 規則,loopback 流量就可能從外部進入。sysctl -a | grep route_localnet 應在每一行顯示 = 0。
實務規則可直接由此推得:只有您自己的應用程式會使用的資料庫、快取或管理面板,應繫結至 127.0.0.1,而不是 0.0.0.0。如果服務從未監聽公開位址,攻擊者就沒有可連線的入口。
正在監聽不代表可以連線
還有一項區別能避免許多混淆。機器上的連接埠已開啟,也就是有程式正在監聽,與該連接埠可從外部連線,也就是防火牆允許連線,是兩回事。遠端用戶端必須同時滿足這兩項條件才能建立連線。從用戶端看來,這兩種失敗情況也不同:遭到拒絕的連線通常表示沒有程式正在監聽;連線持續等待後逾時,通常表示防火牆丟棄了封包,這正是那兩個 SSH 錯誤所表示的情況。
因此,控制分為兩個層級。您可以透過設定各服務的繫結位址,決定哪些服務要監聽。您也可以透過防火牆,決定外部網路可以連到哪些服務。妥善管理的伺服器會同時使用這兩種控制:服務只繫結到必要的位址,而防火牆拒絕所有未明確允許的連線。使用 ss 查看目前監聽的服務是第 1 步;決定防火牆允許哪些連線是第 2 步,詳見UFW 防火牆入門。
這裡有一項容易造成問題的細節。IPv4 與 IPv6 是分開的,如果防火牆只涵蓋 IPv4,就會讓 [::] 服務在 IPv6 上保持開放。這個特定陷阱另有專文說明:IPv6 防火牆陷阱。
FAQ
如何查看 Linux 伺服器上哪些連接埠已開啟?
執行 sudo ss -tlnp 查看 TCP,或執行 sudo ss -ulnp 查看 UDP。這會列出所有監聽中的 socket、連接埠、所繫結的本機位址,以及擁有該 socket 的程序。查看 Local Address 欄位:0.0.0.0 或 [::] 表示服務暴露在網路上,而 127.0.0.1 表示服務只在本機監聽。
0.0.0.0 與 127.0.0.1 有什麼不同?
0.0.0.0 表示「監聽所有 IPv4 位址」,包括公開位址,因此服務可從網路連線。127.0.0.1 是 loopback,也就是機器用來與自身通訊的位址。在核心的預設設定下,其他位置無法透過路由連到此位址,因此繫結到該位址的服務只能從本機連線。將內部服務繫結到 127.0.0.1,讓它們不暴露在網路上。
服務要正常運作,是否需要在防火牆中開啟連接埠?
只有必須讓其他機器連線的服務才需要。繫結到 127.0.0.1 的服務不需要允許規則,因為在核心的預設設定下,外部無法連到它。繫結在 0.0.0.0 或 [::] 的服務,若您的防火牆預設拒絕傳入流量,就需要允許規則,而防火牆應採用這項設定。如果沒有啟用防火牆,或防火牆政策接受所有流量,該服務即使沒有任何規則也已經可以連線。
TCP 連接埠與 UDP 連接埠有什麼不同?
TCP 是連線導向協定,大多數服務都使用 TCP,例如 SSH、網頁伺服器與資料庫。UDP 不需建立連線,常用於 DNS 與部分 VPN。TCP 與 UDP 中的相同號碼是不同的連接埠,因此 53/tcp 與 53/udp 並不相同。撰寫防火牆規則時,必須指定通訊協定,例如 22/tcp。