TCP協議三次握手連線四次握手斷開和DOS攻擊

五柳-先生發表於2015-12-15
TCP連線的狀態圖


TCP建立連線的三次握手過程,以及關閉連線的四次握手過程


貼一個telnet建立連線,斷開連線的使用wireshark捕獲的packet截圖。


1、建立連線協議(三次握手)
(1)客戶 端傳送一個帶SYN標誌的TCP報文到伺服器。這是三次握手過程中的報文1。
(2) 伺服器端迴應客戶端的,這是三次握手中的第2個報文,這個報文同時帶ACK標誌和SYN標誌。因此它表示對剛才客戶端SYN報文的迴應;同時又標誌SYN給客戶端,詢問客戶端是否準備好進行資料通 訊。
(3) 客戶必須再次迴應服務段一個ACK報文,這是報文段3。

2、連線終止協議(四次握手)
   由於TCP連 接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
 (1) TCP客 戶端傳送一個FIN,用來關閉客戶到伺服器的資料傳送(報文段4)。
 (2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
 (3) 伺服器關閉客戶端的連線,傳送一個FIN給客戶端(報文段6)。
 (4) 客戶段發回ACK報文確認,並將確認序號設定為收到序號加1(報文段7)。

CLOSED: 這個沒什麼好說的了,表示初始狀態。
LISTEN: 這個也是非常容易理解的一個狀態,表示伺服器端的某個SOCKET處 於監聽狀態,可以接受連線了。
SYN_RCVD: 這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連線時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程式,故意將三次TCP握手過程中最後一個ACK報文不予傳送。因此這種狀態時,當收到客戶端的ACK報文 後,它會進入到ESTABLISHED狀態。
SYN_SENT: 這個狀態與SYN_RCVD遙想呼應,當客戶端SOCKET執行CONNECT連線時,它首先傳送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的傳送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已傳送SYN報文。
ESTABLISHED:這個容易理解了,表示連線已經建立了。
FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連線,向對方傳送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。
FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你,稍後再關閉連線。
TIME_WAIT: 表示收到了對方的FIN報文,併傳送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。
CLOSING: 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你傳送FIN報文後,按理來說是應該先收到(或同時收到)對方的ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你傳送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時傳送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連線。
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後傳送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有資料傳送給對方,如果沒有的話,那麼你也就可以close這個SOCKET,傳送FIN報文給對方,也即關閉連線。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連線。
LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在傳送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。

補充:
a. 預設情況下(不改變socket選項),當你呼叫close( or closesocket,以下說close不再重複)時,如果傳送緩衝中還有資料,TCP會繼續把資料傳送完。
b. 傳送了FIN只是表示這端不能繼續傳送資料(應用層不能再呼叫send傳送),但是還可以接收資料。
c. 應用層如何知道對端關閉?通常,在最簡單的阻塞模型中,當你呼叫recv時,如果返回0,則表示對端關閉。在這個時候通常的做法就是也呼叫close,那麼TCP層就傳送FIN,繼續完成四次握手。如果你不呼叫close,那麼對端就會處於FIN_WAIT_2狀態,而本端則會處於CLOSE_WAIT狀態。這個可以寫程式碼試試。
d. 在很多時候,TCP連線的斷開都會由TCP層自動進行,例如你CTRL+C終止你的程式,TCP連線依然會正常關閉,你可以寫程式碼試試。

1、 為什麼建立連線協議是三次握手,而關閉連線卻是四次握手呢?
這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裡來傳送。但關閉連線時,當收到對方的FIN報文通知時,它僅僅表示對方沒有資料傳送給你了;但未必你所有的資料都全部傳送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要傳送一些資料給對方之後,再傳送FIN報文給對方來表示你同意現在可以關閉連線了,所以它這裡的ACK報文和FIN報文多數情況下都是分開傳送的。

2、 為什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?
什麼是2MSL?MSL即Maximum Segment Lifetime,也就是報文最大生存時間,引用《TCP/IP詳解》中的話:“它(MSL)是任何報文段被丟棄前在網路內的最長時間。”那麼,2MSL也就是這個時間的2倍,當TCP連線完成四個報文段的交換時,主動關閉的一方將繼續等待一定時間(2-4分鐘),即使兩端的應用程式結束。例如在上面的telnet程式客戶端關閉後,使用netstat檢視的結果:
C:\>netstat -na | find "172.29.21.25"
TCP 172.29.132.60:2795 172.29.21.25:23 TIME_WAIT

為什麼需要這個2MSL呢,
第一,雖然雙方都同意關閉連線了,而且握手的4個報文也都協調和傳送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣);但是因為我們必須要假想網路是不可靠的,你無法保證你最後傳送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。
第二,報文可能會被混淆,意思是說,其他時候的連線可能會被當作本次的連線。直接引用《The TCP/IP Guide》的說法:The second is to provide a “buffering period” between the end of this connection and any subsequent ones. If not for this period, it is possible that packets from different connections could be mixed, creating confusion.

當某個連線的一端處於TIME_WAIT狀態時,該連線將不能再被使用。事實上,對於我們比較有現實意義的是,這個埠將不能再被使用。某個埠處於TIME_WAIT狀態(其實應該是這個連線)時,這意味著這個TCP連線並沒有斷開(完全斷開),那麼,如果你bind這個埠,就會失敗。對於伺服器而言,如果伺服器突然crash掉了,那麼它將無法在2MSL內重新啟動,因為bind會失敗。解決這個問題的一個方法就是設定socket的SO_REUSEADDR選項。這個選項意味著你可以重用一個地址。

當建立一個TCP連線時,伺服器端會繼續用原有埠監聽,同時用這個埠與客戶端通訊。而客戶端預設情況下會使用一個隨機埠與伺服器端的監聽埠通訊。有時候,為了伺服器端的安全性,我們需要對客戶端進行驗證,即限定某個IP某個特定埠的客戶端。客戶端可以使用bind來使用特定的埠。對於伺服器端,當設定了SO_REUSEADDR選項時,它可以在2MSL內啟動並listen成功。但是對於客戶端,當使用bind並設定SO_REUSEADDR時,如果在2MSL內啟動,雖然bind會成功,但是在windows平臺上connect會失敗。而在linux上則不存在這個問題。(我的實驗平臺:winxp, ubuntu7.10)

要解決windows平臺的這個問題,可以設定SO_LINGER選項。SO_LINGER選項決定呼叫close時TCP的行為。SO_LINGER涉及到linger結構體,如果設定結構體中l_onoff為非0,l_linger為0,那麼呼叫close時TCP連線會立刻斷開,TCP不會將傳送緩衝中未傳送的資料傳送,而是立即傳送一個RST報文給對方,這個時候TCP連線(關閉時)就不會進入TIME_WAIT狀態。如你所見,這樣做雖然解決了問題,但是並不安全。通過以上方式設定SO_LINGER狀態,等同於設定SO_DONTLINGER狀態。

當TCP連線發生一些物理上的意外情況時,例如網線斷開,linux上的TCP實現會依然認為該連線有效,而windows則會在一定時間後返回錯誤資訊。這似乎可以通過設定SO_KEEPALIVE選項來解決,不過不知道這個選項是否對於所有平臺都有效。

3. 為什麼不能用兩次握手進行連線?
我們知道,3次握手完成兩個重要的功能,既要雙方做好傳送資料的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被髮送和確認。
現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通訊,假定C給S傳送一個連線請求分組,S收到了這個分組,併傳送了確認應答分組。按照兩次握手的協定,S認為連線已經成功地建立了,可以開始傳送資料分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S是否已準備好,不知道S建立什麼樣的序列號,C甚至懷疑S是否收到自己的連線請求分組。在這種情況下,C認為連線還未建立成功,將忽略S發來的任何資料分組,只等待連線確認應答分組。而S在發出的分組超時後,重複傳送同樣的分組。這樣就形成了死鎖。

DoS攻擊
DoS攻擊、DDoS攻擊和DRDoS攻擊相信大家已經早有耳聞了吧!DoS是Denial of Service的簡寫就是拒絕服務,而DDoS就是Distributed Denial of Service的簡寫就是分散式拒絕服務,而DRDoS就是Distributed Reflection Denial of Service的簡寫,這是分佈反射式拒絕服務的意思。
不過這3中攻擊方法最厲害的還是DDoS,那個DRDoS攻擊雖然是新近出的一種攻擊方法,但它只是DDoS攻擊的變形,它的唯一不同就是不用佔領大量的“肉雞”。這三種方法都是利用TCP三次握手的漏洞進行攻擊的,所以對它們的防禦辦法都是差不多的。

DoS攻擊是最早出現的,它的攻擊方法說白了就是單挑,是比誰的機器效能好、速度快。但是現在的科技飛速發展,一般的網站主機都有十幾臺主機,而且各個主機的處理能力、記憶體大小和網路速度都有飛速的發展,有的網路頻寬甚至超過了千兆級別。這樣我們的一對一單挑式攻擊就沒有什麼作用了,搞不好自己的機子就會死掉。舉個這樣的攻擊例子,假如你的機器每秒能夠傳送10個攻擊用的資料包,而被你攻擊的機器(效能、網路頻寬都是頂尖的)每秒能夠接受並處理100攻擊資料包,那樣的話,你的攻擊就什麼用處都沒有了,而且非常有當機的可能。要知道,你若是傳送這種1Vs1的攻擊,你的機器的CPU佔用率是90%以上的,你的機器要是配置不夠高的話,那你就死定了。
不過,科技在發展,黑客的技術也在發展。正所謂道高一尺,魔高一仗。經過無數次當機,黑客們終於又找到一種新的DoS攻擊方法,這就是DDoS攻擊。它的原理說白了就是群毆,用好多的機器對目標機器一起發動 DoS攻擊,但這不是很多黑客一起參與的,這種攻擊只是由一名黑客來操作的。這名黑客不是擁有很多機器,他是通過他的機器在網路上佔領很多的“肉雞”,並且控制這些“肉雞”來發動DDoS攻擊,要不然怎麼叫做分散式呢。還是剛才的那個例子,你的機器每秒能傳送10攻擊資料包,而被攻擊的機器每秒能夠接受100的資料包,這樣你的攻擊肯定不會起作用,而你再用10臺或更多的機器來對被攻擊目標的機器進行攻擊的話,嘿嘿!結果我就不說了。
DRDoS分佈反射式拒絕服務攻擊這是DDoS攻擊的變形,它與DDoS的不同之處就是DrDoS不需要在攻擊之前佔領大量的“肉雞”。它的攻擊原理和Smurf攻擊原理相近,不過DRDoS是可以在廣域網上進行的,而Smurf攻擊是在區域網進行的。它的作用原理是基於廣播地址與迴應請求的。一臺計算機向另一臺計算機傳送一些特殊的資料包如ping請求時,會接到它的迴應;如果向本網路的廣播地址傳送請求包,實際上會到達網路上所有的計算機,這時就會得到所有計算機的迴應。這些迴應是需要被接收的計算機處理的,每處理一個就要佔用一份系統資源,如果同時接到網路上所有計算機的迴應,接收方的系統是有可能吃不消的,就象遭到了DDoS攻擊一樣。不過是沒有人笨到自己攻擊自己,不過這種方法被黑客加以改進就具有很大的威力了。黑客向廣播地址傳送請求包,所有的計算機得到請求後,卻不會把迴應發到黑客那裡,而是發到被攻擊主機。這是因為黑客冒充了被攻擊主機。黑客傳送請求包所用的軟體是可以偽造源地址的,接到偽造資料包的主機會根據源地址把迴應發出去,這當然就是被攻擊主機的地址。黑客同時還會把傳送請求包的時間間隔減小,這樣在短時間能發出大量的請求包,使被攻擊主機接到從被欺騙計算機那裡傳來的洪水般的迴應,就像遭到了DDoS攻擊導致系統崩潰。駭客藉助了網路中所有計算機來攻擊受害者,而不需要事先去佔領這些被欺騙的主機,這就是Smurf攻擊。而DRDoS攻擊正是這個原理,黑客同樣利用特殊的發包工具,首先把偽造了源地址的SYN連線請求包傳送到那些被欺騙的計算機上,根據TCP三次握手的規則,這些計算機會向源IP發出SYN+ACK或RST包來響應這個請求。同Smurf攻擊一樣,黑客所傳送的請求包的源IP地址是被攻擊主機的地址,這樣受欺騙的主機就都會把迴應發到被攻擊主機處,造成被攻擊主機忙於處理這些迴應而癱瘓。
解釋:
SYN:(Synchronize sequence numbers)用來建立連線,在連線請求中,SYN=1,ACK=0,連線響應時,SYN=1,ACK=1。即,SYN和ACK來區分Connection Request和Connection Accepted。
RST:(Reset the connection)用於復位因某種原因引起出現的錯誤連線,也用來拒絕非法資料和請求。如果接收到RST位時候,通常發生了某些錯誤。
ACK:(Acknowledgment field significant)置1時表示確認號(Acknowledgment Number)為合法,為0的時候表示資料段不包含確認資訊,確認號被忽略。

設我們要準備建立連線,伺服器正處於正常的接聽狀態。
  第一步:我們也就是客戶端傳送一個帶SYN位的請求,向伺服器表示需要連線,假設請求包的序列號為10,那麼則為:SYN=10,ACK=0,然後等待伺服器的迴應。
  第二步:伺服器接收到這樣的請求包後,檢視是否在接聽的是指定的埠,如果不是就傳送RST=1迴應,拒絕建立連線。如果接收請求包,那麼伺服器傳送確認迴應,SYN為伺服器的一個內碼,假設為100,ACK位則是客戶端的請求序號加1,本例中傳送的資料是:SYN=100,ACK=11,用這樣的資料迴應給我們。向我們表示,伺服器連線已經準備好了,等待我們的確認。這時我們接收到迴應後,分析得到的資訊,準備傳送確認連線訊號到伺服器。
  第三步:我們傳送確認建立連線的資訊給伺服器。確認資訊的SYN位是伺服器傳送的ACK位,ACK位是伺服器傳送的SYN位加1。即:SYN=11,ACK=101。
  這樣我們的連線就建立起來了。

DDoS究竟如何攻擊?目前最流行也是最好用的攻擊方法就是使用SYN-Flood進行攻擊,SYN-Flood也就是SYN洪水攻擊。SYN-Flood不會完成TCP三次握手的第三步,也就是不傳送確認連線的資訊給伺服器。這樣,伺服器無法完成第三次握手,但伺服器不會立即放棄,伺服器會不停的重試並等待一定的時間後放棄這個未完成的連線,這段時間叫做SYN timeout,這段時間大約30秒-2分鐘左右。若是一個使用者在連線時出現問題導致伺服器的一個執行緒等待1分鐘並不是什麼大不了的問題,但是若有人用特殊的軟體大量模擬這種情況,那後果就可想而知了。一個伺服器若是處理這些大量的半連線資訊而消耗大量的系統資源和網路頻寬,這樣伺服器就不會再有空餘去處理普通使用者的正常請求(因為客戶的正常請求比率很小)。這樣這個伺服器就無法工作了,這種攻擊就叫做:SYN-Flood攻擊。

到目前為止,進行DDoS攻擊的防禦還是比較困難的。首先,這種攻擊的特點是它利用了TCP/IP協議的漏洞,除非你不用TCP/IP,才有可能完全抵禦住DDoS攻擊。不過這不等於我們就沒有辦法阻擋DDoS攻擊,我們可以盡力來減少DDoS的攻擊。下面就是一些防禦方法:
1.確保伺服器的系統檔案是最新的版本,並及時更新系統補丁。
2.關閉不必要的服務。
3.限制同時開啟的SYN半連線數目。
4.縮短SYN半連線的time out 時間。
5.正確設定防火牆
6.禁止對主機的非開放服務的訪問
7.限制特定IP地址的訪問
8.啟用防火牆的防DDoS的屬性
9.嚴格限制對外開放的伺服器的向外訪問
10.執行埠對映程式禍埠掃描程式,要認真檢查特權埠和非特權埠。
11.認真檢查網路裝置和主機/伺服器系統的日誌。只要日誌出現漏洞或是時間變更,那這臺機器就可能遭到了攻擊。

12.限制在防火牆外與網路檔案共享。這樣會給黑客擷取系統檔案的機會,主機的資訊暴露給黑客,無疑是給了對方入侵的機會。

轉載: http://blog.csdn.net/fw0124/article/details/7452695

相關文章