章節概覽#

本章探討位於 application layer 的網路應用程式,包括用戶端(client)與伺服器端(server)。這一層位於網路堆疊的最頂層,最貼近終端使用者。章節涵蓋了基本的網路服務運作原理、常見伺服器(特別是 SSH)、診斷工具、網路安全概念,以及 socket 程式設計基礎。

網路用戶端透過作業系統的 transport layer 協定(TCP 和 UDP)連接到對應的伺服器。伺服器程式可以直接監聽 port,也可以透過次級伺服器來運作。


10.1 服務的基礎#

TCP 服務建立在簡單、不間斷的雙向資料串流之上。最直接的方式是用 telnet 連接到未加密的 web server:

$ telnet example.org 80

連線成功後,輸入 HTTP 請求:

GET / HTTP/1.1
Host: example.org

按兩次 ENTER 後,伺服器會回傳 HTML 內容。這個練習示範了:

  • 遠端主機有一個 web server process 正在監聽 TCP port 80
  • telnet 是發起連線的用戶端

telnet 原本是設計用來遠端登入的,但 telnet 遠端登入伺服器完全不安全。不過 telnet 用戶端對於除錯遠端 TCP 服務仍然很有用。它無法用於 UDP 或 TCP 以外的 transport layer。若需要通用網路用戶端,可考慮使用 netcat


10.2 深入觀察#

使用 curl 這個了解 HTTP application layer 協定的命令列工具,可以記錄通訊細節:

$ curl --trace-ascii trace_file http://www.example.org/

從 trace 檔案可以觀察到:

  • curl 先在 transport layer 建立 TCP 連線
  • 然後在 application layer 發送 HTTP 請求(header)
  • 伺服器先回傳 response header,再回傳實際文件內容
  • header 與 data 之間以空白行分隔

作業系統在處理封包時並不區分 header 和 data,這些區別完全在 user-space 的應用程式內部處理。對 OS 來說,這些都只是資料串流。


10.3 網路伺服器#

大多數網路伺服器的運作方式類似其他 daemon,差別在於它們與 network port 互動。常見的網路伺服器包括:

  • httpd, apache, apache2, nginx — Web 伺服器
  • sshd — Secure Shell daemon
  • postfix, qmail, sendmail — 郵件伺服器
  • cupsd — 列印伺服器
  • nfsd, mountd — 網路檔案系統 daemon
  • smbd, nmbd — Windows 檔案分享 daemon
  • rpcbind — RPC portmap 服務 daemon

伺服器通常以多行程方式運作:監聽行程收到新連線時,使用 fork() 建立 worker 子行程來處理該連線。高效能伺服器(如 Apache)可能在啟動時預先建立多個 worker process。

10.3.1 Secure Shell#

SSH 是遠端存取 Unix 機器的事實標準,取代了不安全的 telnetrlogin。SSH 使用 public-key cryptography 進行身份驗證,並加密所有 session 資料。

SSH 的主要功能:

  • 加密密碼和所有 session 資料
  • Tunnel 其他網路連線(包括 X Window System)
  • 支援幾乎所有作業系統的用戶端
  • 使用 key 進行主機驗證

OpenSSH 是最常見的實作,用戶端程式為 ssh,伺服器端為 sshd。目前只支援 SSH protocol version 2。

Public-key cryptography:與對稱加密不同,public key 只能加密訊息但無法解密,只有對應的 private key 才能解密。這使得金鑰管理更容易,因為 private key 不需要傳輸。

10.3.2 sshd 伺服器#

sshd 伺服器的設定檔位於 /etc/ssh/ 目錄,伺服器設定檔為 sshd_config(注意不要與用戶端的 ssh_config 混淆)。

重要的設定參數:

  • HostKey — 指定 host key 檔案
  • PermitRootLogin — 是否允許 root 透過 SSH 登入
  • LogLevel — syslog 記錄層級(預設 INFO)
  • X11Forwarding — 是否啟用 X Window System tunneling

建立 Host Keys:OpenSSH 使用 RSA 和 DSA 公鑰演算法,每組金鑰包含公鑰(.pub)和私鑰。

# ssh-keygen -t rsa -N '' -f /etc/ssh/ssh_host_rsa_key
# ssh-keygen -t dsa -N '' -f /etc/ssh/ssh_host_dsa_key

絕對不要讓任何人看到 private key,即使是在你自己的系統上。如果有人取得了 private key,你的系統就有被入侵的風險。

啟動 SSH 伺服器

# systemctl enable sshd
# systemctl start sshd

10.3.3 fail2ban#

在網際網路上開放 SSH 伺服器會不斷收到暴力破解攻擊。fail2ban 透過監控 log 訊息,在偵測到某主機在一定時間內多次登入失敗後,使用 iptables 建立規則封鎖該主機的流量。

10.3.4 SSH 用戶端#

登入遠端主機:

$ ssh remote_username@remote_host

透過 SSH 傳輸資料(pipe):

$ tar zcvf - dir | ssh remote_host tar zxvf -

用戶端設定檔為 /etc/ssh/ssh_config。最常見的問題是 known_hosts 中的 public key 與遠端主機不匹配,通常是因為遠端主機更換了金鑰。

SSH 檔案傳輸工具

  • scp — 類似 cp 的安全複製工具
  • sftp — 類似 FTP 的安全檔案傳輸工具
$ scp user@host:file .
$ scp file user@host:dir

如果需要比 scpsftp 更多功能(例如頻繁傳輸大量檔案),可以考慮使用 rsync


10.4 systemd 之前的網路連線伺服器:inetd/xinetd#

在 systemd 和 socket unit 普及之前,inetd 是一種 superserver,負責標準化伺服器程式與 network port 之間的介面。inetd 讀取設定檔並監聽定義的 port,當新連線進入時,將其附加到新啟動的 process。

xinetd 是 inetd 的改良版本,提供更好的存取控制,但已幾乎完全被 systemd 取代。

iptables 等較低階防火牆流行之前,許多管理員使用 TCP wrappertcpd/etc/hosts.allow/etc/hosts.deny)來控制網路服務存取。這套系統現在已經大致淘汰。


10.5 診斷工具#

10.5.1 lsof#

lsof 不僅可以追蹤開啟的檔案,也能列出正在使用或監聽 port 的程式:

# lsof -i

依協定和 port 過濾:

# lsof -iTCP:443

依連線狀態過濾,例如只顯示監聽中的 TCP process:

# lsof -iTCP -sTCP:LISTEN
  • 使用 -n 停用名稱解析以加速輸出
  • 使用 -P 停用 /etc/services 的 port 名稱查詢

10.5.2 tcpdump#

tcpdump 將網路介面設為 promiscuous mode,報告每個通過的封包:

# tcpdump

使用 filter 過濾封包:

# tcpdump tcp
# tcpdump udp or port 80 or port 443

常用的 primitives

  • tcp / udp — TCP 或 UDP 封包
  • ip / ip6 — IPv4 或 IPv6 封包
  • port port — 指定 port 的 TCP/UDP 封包
  • host host — 來自或送往指定主機的封包
  • net network — 來自或送往指定網路的封包

可使用 andor!operator 組合條件。

使用 tcpdump 時要注意:雖然現在大部分重要的網路流量都透過 TLS 加密,但你不應該在未經授權的情況下嗅探他人網路。

10.5.3 netcat#

netcat(或 nc)是一個比 telnet 更靈活的通用網路工具,可以:

  • 連接遠端 TCP/UDP port
  • 指定本地 port 並監聽
  • 掃描 port
  • 重新導向標準 I/O 到網路連線
$ netcat host port
$ netcat -l port_number
  • 使用 -u 選項指定 UDP 而非 TCP
  • 使用 -4-6 強制指定 IPv4 或 IPv6

10.5.4 Port Scanning#

Nmap(Network Mapper)掃描機器上所有 port 以尋找開放的服務:

$ nmap 10.1.2.2

如果你要掃描的網路由他人管理,請先取得許可。網路管理員會監控 port scan 行為,且通常會限制掃描機器的存取。

建議從至少兩個位置進行掃描:本機和本地網路外部的機器,以了解防火牆的封鎖情況。Nmap 也支援以 -6 選項掃描 IPv6 port。


10.6 Remote Procedure Calls#

RPC(Remote Procedure Call)是 application layer 底層的系統,讓程式可以呼叫在遠端伺服器上執行的函式。每種遠端伺服器程式由一個 program number 識別。

RPC 使用 TCP 和 UDP 等 transport protocol,並需要 rpcbind 服務來將 program number 對應到 TCP/UDP port。

$ rpcinfo -p localhost

NFS(Network File System)和 NIS(Network Information Service)都使用 RPC。雖然在獨立機器上不必要,但 RPC 持續存在,例如 GNOME 的 File Access Monitor (FAM) 就需要 rpcbind。


10.7 網路安全#

Linux 作為流行的伺服器平台,容易成為攻擊目標。基本的安全守則:

  • 盡量減少執行的服務 — 不使用的服務就不要開啟
  • 盡量使用防火牆封鎖 — 內部服務(如 RPC port 111)不應暴露在外
  • 追蹤對外提供的服務 — 保持軟體更新,取得安全警報
  • 使用 LTS(長期支援)發行版 — 安全團隊主要關注穩定版本
  • 不給不需要的人帳號 — 本機存取比遠端入侵更容易提權
  • 避免安裝來路不明的套件 — 可能包含 Trojan horse

三種基本的網路攻擊類型:

  • Full compromise — 取得 superuser 存取權限(完全控制)
  • Denial-of-service (DoS) attack — 癱瘓網路服務或使電腦故障
  • Malware — 惡意軟體(Linux 使用者較少受影響,但 Linux malware 確實存在)

10.7.1 常見漏洞#

  • Direct attack — 直接攻擊未受保護的服務,例如 buffer overflow exploit(已被 ASLR 等技術部分緩解)
  • Cleartext password sniffing attack — 擷取以明文傳輸的密碼

應該停用的不安全服務:

  • ftpd — FTP 伺服器漏洞多,且使用明文密碼
  • telnetd, rlogind, rexecd — 所有遠端 session 資料以明文傳輸

若需要為不支援加密的服務提供加密,可以使用 Stunnel 作為加密 wrapper。

10.7.2 安全資源#

  • SANS Institute — 安全訓練、漏洞週報
  • CERT Division(Carnegie Mellon University)— 最嚴重問題的資訊
  • Insecure.org — Nmap 和各種網路漏洞測試工具

如果對網路安全有興趣,應學習 TLS(Transport Layer Security)及其前身 SSL(Secure Socket Layer),它們透過 public-key encryption 和 certificate 來保護網路交易。


10.8 展望#

如果想實際操作較複雜的網路伺服器,常見的選擇有 Apachenginx web server 和 Postfix 郵件伺服器。如果機器位於防火牆或 NAT router 後方,可以安心實驗各種設定。

本章從 kernel space 逐漸轉向 user space,後續章節將更深入介紹 socket 如何橋接 kernel 的 transport layer 和 user-space application layer。


10.9 Network Sockets#

Socket 是 process 透過 kernel 存取網路的介面,也是 user space 與 kernel space 之間的邊界,常用於 interprocess communication (IPC)。

不同的 socket 類型對應不同的網路存取方式:

  • SOCK_STREAM — TCP 連線(stream socket)
  • SOCK_DGRAM — UDP 連線(datagram socket)

Figure 10-1: One method for accepting and processing incoming connections

伺服器處理連入連線的典型流程:

  1. Master process 使用 listener socket 監聽網路連線
  2. 偵測到新連線後,呼叫 accept() 建立專用的 read/write socket
  3. 使用 fork() 建立子行程處理該連線
  4. 原始的 listener socket 繼續監聽新連線

Socket 的彈性在於:如果需要更改底層 transport layer,只需修改初始化程式碼,收發資料的部分大致不需變動。


10.10 Unix Domain Sockets#

不是所有使用網路機制的應用程式都需要連接兩台不同的主機。Unix domain socket 是一種特殊的 socket,用於同一台機器上 process 之間的通訊(IPC),例如 systemd 和 NetworkManager 透過 D-Bus 溝通。

Unix domain socket 的特點:

  • 不是真正的 network socket,背後沒有網路,甚至不需要設定網路
  • 行為類似 network socket:可以監聽、接受連線,選擇類似 TCP 或 UDP 的行為
  • 不一定需要綁定到 socket 檔案,也可以建立 unnamed socket
  • 效能更好,因為 kernel 不需要經過完整的網路子系統

開發者偏好 Unix domain socket 的兩個原因:

  1. 可利用檔案系統權限控制存取
  2. 無網路互動,更簡單且較不容易受到網路入侵

例如 D-Bus 的 socket 檔案位於 /var/run/dbus/,MySQL 的 Unix domain socket 位於 /var/run/mysqld/mysqld.sock

查看系統上的 Unix domain socket:

# lsof -U