Linux——網絡應用與服務

網絡應用與服務

客戶端必須與它們相應的網絡服務器連接起來才能正常工作。Unix服務器有很多種形式。服務器程序直接或間接地監聽端口。另外,服務器功能各異,但沒有通用的配置數據庫。大多數服務器通過配置文件(儘管格式不統一)來定義自身的行爲,並使用操作系統的syslog服務來記錄日誌。接下來我們會介紹一些常見的服務器以及用於調試的工具。

服務的基本概念

TCP服務是最好理解的概念之一,因爲它建立在簡單、無中斷的雙路數據流之上。或許最佳的解釋方式,是讓你直接通過TCP與某個Web服務器的80端口溝通,去看看數據是如何在該連接上移動的。例如,用以下命令連接一個Web服務器:

$ telnet www.wikipedia.org 80

你會得到類似這樣的輸出:

Trying some address...
Connected to www.wikipedia.org.
Escape character is '^]'.

現在輸入:

GET / HTTP/1.0

這個測試告訴我們:

  • 遠程主機那裏有個Web服務器進程監聽着TCP端口80;
  • telnet是初始化這個連接的客戶端。

輸入剖析

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

你會得到大量的HTML輸出。忽略它們(或將它們重定向到/dev/null),並去看看剛剛創建出來的文件trace_file。假設連接成功,那麼文件的開頭部分看起來應該是下面這樣的,表明剛開始時curl嘗試跟該服務器建立TCP連接:

== Info: About to connect() to www.wikipedia.org port 80 (#0)
== Info: Trying 10.80.154.224... == Info: connected

至此你看到的一切都是發生在傳輸層或其下層的。然而,如果連接成功了,那麼curl就會嘗試發送請求(即“報頭”);這裏就開始有應用層了。

=> Send header, 167 bytes (0xa7)
0000: GET / HTTP/1.1
0010: User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenS
0050: SL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
007f: Host: www.wikipedia.org
0098: Accept: */*
00a5:

上例第一行是curl的調試信息輸出,告訴了你它接下來要做的事情。剩下的行展示了curl發送給服務器的信息。開頭的十六進制數只是一個調試偏移量,告訴你收發的數據有多少。

你可以看到curl先發了一個GET命令給服務器(就像用telnet那樣),接着是一些有關服務器的額外信息以及一個空行。然後服務器迴應了,首先是它的報頭(粗體部分)。

<= Recv header, 17 bytes (0x11)
0000: HTTP/1.1 200 OK
<= Recv header, 16 bytes (0x10)
0000: Server: Apache
<= Recv header, 42 bytes (0x2a)
0000: X-Powered-By: PHP/5.3.10-1ubuntu3.9+wmf1
--snip--

跟之前那段輸出很像,<=開頭的行是調試信息,0000:是偏移量

服務器迴應的報頭可以很長,然後,某行的報頭出現了我們請求的內容,就像下面這樣:

<= Recv header, 55 bytes (0x37)
0000: X-Cache: cp1055 hit (16), cp1054 frontend hit (22384)
<= Recv header, 2 bytes (0x2)
0000:
<= Recv data, 877 bytes (0x36d)
0000: 008000
0008: <!DOCTYPE html>.<html lang="mul" dir="ltr">.<head>.<!-- Sysops:
--snip--

儘管調試信息裏有Recv header和Recv data,意味着服務器返回的信息可分爲兩種,但curl向操作系統獲取這兩種信息的方法卻沒有不同,操作系統對它們的處理方式也沒有不同,甚至底層網絡對它們的數據包的處理方式也是一樣的。如果說有不同,那完全是在用戶空間的curl內部。curl讀取報頭的時候,如果發現了標誌HTTP報頭
結束的空行(即中間的兩個字節),它就知道接下來將是真正的應答內容了。

在服務器發送數據方面也同樣如此。服務器並不區分發給操作系統的報頭和內容,區分只發生於用戶空間的服務器程序。

網絡服務器

大多數網絡服務器跟cron之類的服務器守護進程很像,只不過網絡服務器是與網絡端口進行交互的。

以下是一些常見的網絡服務器,在你係統中可能也會見到

  • httpd、apache、apache2:Web服務器。
  • sshd:Secure shell守護進程。
  • postfix、qmail、sendmail:郵件服務器。
  • cupsd:打印服務器。
  • nfsd、mountd:網絡文件系統(文件共享)守護進程。
  • smbd、nmbd:文件共享守護進程
  • rpcbind:遠程程序調用(RPC)端口映射服務守護進程。

大多數網絡服務器有一個共同的特性,即它們通常是多進程的。其中至少有一個進程在監聽網絡端口,而當它接收到一個新的連接時,就會使用fork()來創建一個子進程,負責那個新的連接。該子進程,也叫輔助進程,會隨着連接的終止而終止。同時,監聽進程會繼續接收連接。這樣,一個服務器就能輕鬆地處理多個連接,一般不會有什麼問題。

然而,這個模型也會有一些異常情況。調用fork()是會增加系統負擔的,而高性能TCP服務器(如Apache Web服務器)能在啓動時就創建一定數量的輔助進程,以備連接需要。接受UDP包的服務器只會簡單地接收數據並對其做出反應,它們不需要維持連接。

SSH

SSH是最常見的網絡服務應用之一,它是一種遠程連接Unix機器的標準。配置好之後,我們就能通SSH進行安全的shell登錄、執行遠程程序、共享簡單的文件等。

SSH還憑藉公鑰認證和簡單的會話加密,取代了舊的、不安全的遠程登錄系統telnet和rlogin。大多數ISP和雲提供商都要求以SSH來使用他們的服務,另外很多基於Linux的網絡設備(如NAS)也是這樣要求的。OpenSSH(http://www.openssh.com/)是一個比較流行的、針對Unix的SSH實現,而且幾乎所有的Linux發行版也預裝了它。OpenSSH的客戶端是ssh,服務器是sshd。SSH協議有兩個主要版本:1和2。OpenSSH對兩者都支持,但1是很少用的。

SSH的功能和特性使它能做到以下事情。

  • 對密碼和會話內容加密,保護你不受竊聽困擾。
  • 作爲其他網絡連接的管道,包括來自X Window客戶端的連接。X會在第14章詳細介紹。
  • 幾乎所有操作系統都可用SSH連接。
  • 使用密鑰做主機認證。

但SSH也有缺點。其中一個就是,若想建立SSH連接,你必須先知道遠程主機的公鑰,它是不需要通過什麼保密的渠道就能獲得的(當然你也可以手動檢查它的真假)

SSHD服務器

運行sshd需要一個配置文件以及主機密鑰。大多數發行版都將配置文件放在/etc/ssh配置目錄中,並在你安裝它們的sshd包時,嘗試將一切都配置好。(這裏的配置文件名sshd_config跟客戶端的文件名ssh_config很容易混淆,請注意區分。)

Port 22
#Protocol 2,1
#ListenAddress 0.0.0.0
#ListenAddress ::
HostKey /etc/ssh/ssh_host_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key

以#開頭的是註釋,而sshd_config中的很多的註釋都暗示了默認值。sshd_config(5)手冊包含了所有可選值的解釋,而以下這些是最重要的。

  • HostKey file:使用file作爲主機密鑰。(主機密鑰是短的。)
  • LogLevel level:按照syslog的級別level來記錄信息。
  • PermitRootLogin value:value爲yes則允許超級用戶通過SSH登錄,否則不允許。
  • SyslogFacility name:按syslog設施的名字name來記錄信息。
  • X11Forwarding value:若value爲yes則允許X Window客戶端被SSH管道接駁。
  • XAuthLocation path:設置xauth的路徑。找不到路徑的話,X11的SSH管道將無法工作。如果xauth不在/usr/bin裏,則需寫明xauth的完整路徑。

主機密匙

OpenSSH有三套主機密鑰:一套用於版本1的協議,另兩套用於版本2。每套都有一個公鑰(擴展名爲.pub的文件)和一個私鑰(無擴展名)。不要讓任何人知道你的私鑰,否則就有被入侵的危險。

SSH版本1只有RSA密鑰,而版本2則有RSA和DSA。RSA和DSA都是公鑰加密算法。

文件名 密鑰類型
ssh host_rsa_key RSA私鑰(版本2)
ssh host_rsa_key.pub RSA公鑰(版本2)
ssh host_dsa_key DSA私鑰(版本2)
ssh host_dsa_key.pub DSA公鑰(版本2)
ssh host_key RSA私鑰(版本1)
ssh host key.pub RSA公鑰(版本1)

SSH服務器與客戶端還用到了一個叫作ssh_known_hosts的密鑰文件,裏面包含了其他主機的公鑰。如果你要使用基於主機的認證,服務器端的ssh_known_hosts必須要包含所有可信客戶端的公鑰。瞭解密鑰文件有助於你更換機器。當你從頭給機器安裝系統時,你可以用回舊的機器上的密鑰文件,這樣用戶就能跟舊的密鑰配置對上了。

開啓SSH服務器

儘管大多數發行版都帶有SSH,但默認卻不會啓動sshd服務器。在Ubuntu和Debian上,安裝SSH服務器就會創建密鑰、啓動服務,並在開機腳本中加上啓動SSH。在Fedora上,sshd是預裝的,但默認是關閉的。想在開機時啓動sshd,可以用chkconfig(但這並不會讓服務器馬上啓動,除非你用service sshd start):

# chkconfig sshd on

Fedora一般會在sshd初次啓動時補建漏掉的密鑰文件。
如果你還沒裝好init的支持,就用root來運行sshd,以啓動服務器。而一旦啓動,sshd就會在/var/run/sshd.pid記下自己的PID。

你還可以在systemd或用inetd以套接字單元來啓動sshd,但這不是個好方法,因爲服務器偶爾會產生密鑰文件,這個進程可能會很費時間。

SSH客戶端

想登錄遠程主機,運行:

ssh remote_username@host

如果你在本機的賬號跟遠程的一樣,可以省略remote_username@。你還可以像下面例子一樣用管道符來連接ssh命令,將一個叫dir的目錄複製到另一臺主機:

tar zcvf - dir | ssh remote_host tar zxvf -

全局的SSH客戶端配置文件ssh_config應該在/etc/ssh裏,就如sshd_config文件一樣。跟服務器配置文件類似,客戶端配置文件也有鍵值對,但你應該不用去改它。

SSH文件傳輸客戶端

OpenSSH包含了文件傳輸程序:scp和sftp。這兩個命令用以取代舊的、不安全的命令rcp和ftp。

你可以用scp在本機和遠程主機之間傳輸文件,它就像cp命令一樣。以下是一些例子。

$ scp user@host:file .
$ scp file user@host:dir
$ scp user1@host1:file user2@host2:dir

sftp程序就好比是命令行的ftp客戶端,它有get和put命令。遠程主機必須裝好sftp-server程序(如果遠端裝了OpenSSH,那通常都會帶上這個)。

非Unix平臺的SSH客戶端

PuTTY是一個不錯的基本Windows客戶端,它包含了安全的文件複製程序。MacSSH適用於Mac OS 9.x及以下版本。Mac OS X是基於Unix的,也包含OpenSSH

守護進程inetd和xinetd

爲每種服務實現獨立的服務器好像並不太高效。每個服務器都要分別配置端口監聽、訪問控制以及端口設置。大多數服務的配置方式都是一樣的,只是處理連接的方式不同。

傳統的解決方法是使用inetd守護進程,它是一種超級服務器,用於規範網絡端口的接入和服務器程序與網絡端口之間的接口。啓動inetd之後,它會讀取自己的配置文件,並監聽其中提到的網絡端口。當連接到來時,inetd就會新開一個進程來處理它。

xinetd是inetd的新版本,它提供更簡單的配置和更優秀的訪問控制,但xinetd正被systemd取代,systemd的套接字單元能提供同樣的功能。

ident stream tcp nowait root /usr/sbin/sshd sshd -i

其中7個字段從左至右含義分別如下所示。

  • 服務名稱:來自/etc/services(見9.14.3節)。
  • 套接字類型:通常TCP是stream,UDP是dgram。
  • 協議:傳輸協議,通常是tcp或udp。
  • 數據報服務器行爲:UDP可選wait或nowait。其他傳輸協議應該用nowait。
  • 用戶:運行該服務的用戶。加上.group的話,可以指定羣組。
  • 可執行程序:inetd爲應付該服務而發起的程序。
  • 參數:可執行程序的參數。第一個參數是該程序的名字。

診斷工具

tcpdump

如果你想明確地知道你的網絡上有什麼在流通,你可用tcpdump將網絡接口置於混雜模式,並向你報告每一個通過的數據包。不帶參數地運行tcpdump,就包含了ARP請求和Web連接。

你可以加入過濾器,以讓tcpdump的內容更精確。過濾器可以是源主機、目標主機、網絡、以太網地址、各層協議等等。各種數據包協議中,tcpdump能認出的有:ARP、RARP、ICMP、TCP、UDP、IP、IPv6、AppleTalk、IPX。例如,讓tcpdump只輸出TCP數據包,可運行:

# tcpdump tcp

想看網頁包和UDP包,運行:

# tcpdump udp or port 80

netcat

netcat可以與TCP和UDP端口通信,指定本地端口,監聽端口,掃描端口,對網絡輸入輸出重定向到標準輸入輸出等等。

用netcat連接TCP端口

$ netcat host port

netcat只在對方關閉連接時終止,所以如果你用netcat接收標準輸入,就會有點麻煩。你可以使用CTRL-C來隨時關閉連接。(如果你希望由標準輸入流來決定程序和網絡連接的關閉,可以改用sock程序。)

掃描端口

有時你可能想知道你網絡中的機器正提供着什麼服務,或哪個IP正在被使用,這時你可以用網絡映射器(Network Mapper,以下簡稱Nmap)程序來掃描並列舉出一臺機器(或一個網絡中的機器)的開放端口。

在列舉你機器的端口時,至少從這樣兩個不同的角度來運行Nmap程序會更好:從本機和從另一臺機器(可能是本地網絡之外的)。這樣做可以看到你防火牆屏蔽了什麼。

運行nmap host來對一個主機進行端口掃描,例如:

$ nmap 10.1.2.2
Starting Nmap 5.21 ( http://nmap.org ) at 2015-09-21 16:51 PST
Nmap scan report for 10.1.2.2
Host is up (0.00027s latency).
Not shown: 993 closed ports
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
80/tcp open http
111/tcp open rpcbind
8800/tcp open unknown
9000/tcp open cslistener
9090/tcp open zeus-admin
Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds

遠程程度調用

RPC意指遠程程序調用(Remote Procedure Call),是應用層中較低層的一個系統。它是爲了方便程序員訪問網絡應用而設計的,能使本地程序調用遠程程序(按程序號來標識),讓遠程程序返回結果碼或信息。

RPC的實現需要用到傳輸層協議,如TCP和UDP。它需要一種特別的中介服務來將程序號與TCP和UDP的端口號對應起來。這種服務就是rpcbind,運行RPC服務就需要用到它。

$ rpcinfo -p localhost

RPC是一種難以消亡的協議。網絡文件系統(Network File System,以下簡稱NFS)和網絡信息服務(Network Information Service,以下簡稱NIS)就用得到它,但單機環境下是不需要這些服務的。當你以爲你已經對rpcbind不會再有任何需要時,就會有些依賴它的東西出現,例如GNOME的文件訪問監控(File Access Monitor,以下簡稱FAM)。

網絡安全

因爲Linux是PC平臺上風行的Unix系統,尤其是它被廣泛用作網頁服務器,所以它也招致了很多黑客攻擊

網絡安全帶來了兩個極端:真心想攻破系統的人(不管是爲了錢還是爲了好玩)和精心設計防禦方案的人(這個也很有利可圖)。幸好,你不需要了解太多東西來維持系統的安全。這裏有一些經驗法則。

  • 打開的服務越少越好:黑客不能攻擊你機器上不存在的服務。如果你知道有哪個服務是你不需要的,那就別打開它,等你真正用到那個服務時再打開。
  • 防火牆屏蔽得越多越好:Unix系統有一些內部服務是你可能不知道的(例如用於RPC端映射的TCP端口111),因此也別讓其他機器知道它們的存在。跟蹤和規範本機的服務是很困難的,因爲監聽的程序和被監聽的端口錯綜複雜。爲避免黑客發現你係統上的內部服務,請使用有效的防火牆規則,併爲路由器安裝防火牆。
  • 記錄你提供給互聯網的服務:如果你運行着SSH服務器、Postfix或類似的東西,請保持你軟件的更新,以及使用合適的安全警報
  • 讓服務器使用“長期支持”的系統版本:安全團隊一般在穩定、有支持的系統版本上才能集中精力工作。開發版或測試版如Debian Unstable和Fedora Rawhide不太受他們關注。
  • 賬號不要發給不用的人:通過本地賬號獲取超級用戶的權限,比遠程入侵要簡單得多。事實上,大多數系統上的軟件都有這樣那樣的漏洞,只要你能登錄shell,就有可能獲取超級用戶的權力。不要指望你的朋友懂得如何保護密碼(或懂得使用複雜的密碼)。
  • 避免安裝可疑的二進制包:它們可能包含木馬

有以下三種基本的網絡攻擊。

  • 全面威脅:意思是獲取了超級用戶的權限(對一臺機器完全掌控)。黑客可以通過服務攻擊,例如緩存溢出、接管一個沒什麼保護措施的賬號或利用一個寫得不太好的setuid,來做到“全面威脅”。
  • 拒絕服務(Denial-of-service,簡稱DoS)攻擊:這使得機器無法繼續提供服務,或無需通過登錄就用某些方法造成機器故障。這種攻擊更難防範,但很容易應對。
  • 惡意軟件:Linux用戶大多對惡意軟件(如電子郵件蠕蟲和病毒)免疫,只因爲他們的電子郵件客戶端不會蠢到運行附件裏的程序。但Linux惡意程序確實存在。請勿從陌生的地方下載並安裝二進制軟件。

典型漏洞

直接攻擊和嗅探明文密碼

直接攻擊:就是擺明要攻陷一臺機器。最常見的做法是利用緩存溢出。該漏洞是因爲粗心的程序員沒檢查數組邊界而造成的。攻擊者在一大堆數據中編造一個棧幀,然後送到遠程服務器,並期望它溢出而覆蓋了程序,最終導致服務器執行了棧幀中的東西。儘管這不太容易,但卻很容易複製。

嗅探明文密碼:是指獲取網絡上明文傳輸的密碼。一旦攻擊者拿到你的密碼,那你就玩完了。從那開始,攻擊者就會直接登入,嘗試獲取超級用戶的權限(這比遠程攻擊要簡單),或以該機器攻擊其他機器,或用其他機器攻擊該機器

有些服務因爲設計缺陷而經常成爲攻擊目標。例如以下這些服務:

  • ftpd:不管什麼原因,所有的FTP服務器都存在漏洞。除此之外,大多數FTP服務器都用明文密碼。如果你要在機器之間移動文件,考慮下基於SSH的方案或rsync服務器。
  • telnetd、rlogind、rexecd:它們都把會話內容(包括密碼)用明文傳輸。不要使用它們,除非你有Kerberos版本。
  • fingerd:黑客可以通過finger服務獲取用戶列表和其他信息。

安全資源

安全網站:

  • http://www.sans.org/:提供培訓、服務、免費的高危漏洞週報、安全策略樣板等等。
  • http://www.cert.org/:這裏介紹最危險的漏洞。
  • http://www.insecure.org/:這裏有Nmap和各種網絡開發測試工具,比其他網站做得更詳盡、更開放。

套接字:進程與網絡的通信方式

在Unix上,進程是用套接字來標識與網絡通信的時機與方式的。套接字是進程通過內核訪問網絡的接口,它代表用戶空間與內核空間的邊界。它也常被用於進程間通信(Interprocess Communication,以下簡稱IPC)。

因爲進程需要以不同的方式訪問網絡,所以套接字也分不同種類。例如,TCP連接會用流式套接字(程序員稱之爲SOCK_STREAM),而UDP連接則用數據報套接字(SOCK_DGRAM)。

建立網絡套接字有點複雜,因爲你有時需要知道套接字類型、IP地址、端口、傳輸協議。然而,當所有初始的細節整理好後,服務器就能用相應的標準模型來處理網絡通信了。

監聽套接字和讀寫套接字。主進程用監聽套接字在網絡中尋找連接。當一個新的連接到來,主進程就用accept()系統調用來接收該連接,它能爲連接創建專用的讀寫套接字。接着主進程用fork()創建一個新的子進程來處理該連接。最終,監聽套接字繼續監聽,爲主進程帶來更多連接。
在這裏插入圖片描述

Unix域套接字

進程間的通信可以使用本地主機(127.0.0.1)來做常規的網絡通信,但我們一般使用另一種特別的套接字,進程與Unix域套接字的連接幾乎與網絡套接字連接一樣:進程可以監聽和接收套接字上的連接,還可以選擇不同類型的套接字來實現TCP式或UDP式的工作方式。

對開發者的好處

  1. 開發者可以通過管理套接字文件的訪問權限來管理Unix域套接字的訪問權限。也就是說,不能訪問某個套接字文件的進程,也就不能使用該套接字。
  2. 因爲Linux內核與Unix域套接字通信並不需要經歷網絡層次,所以性能會比網絡套接字好。

爲Unix域套接字寫代碼跟支持一般的網絡套接字沒多大不同。因爲它的好處十分明顯,所以有些網絡服務器會同時提供網絡套接字和Unix域套接字的連接。例如,MySQL的數據庫服務器mysqld能接受遠端的連接,同時也以/var/run/mysqld/mysqld.sock提供Unix域套接字。

列出Unix域套接字

你可以使用lsof -U來查看系統正在使用中的Unix域套接字:

# lsof -U
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 19701 mysql 12u unix 0xe4defcc0 0t0 35201227 /var/run/mysqld/mysqld.sock
chromium- 26534 juser 5u unix 0xeeac9b00 0t0 42445141 socket
tlsmgr 30480 postfix 5u unix 0xc3384240 0t0 17009106 socket
tlsmgr 30480 postfix 6u unix 0xe20161c0 0t0 10965 private/tlsmgr
--snip--
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章