什么是SYN Flood攻擊?


SYN Flood (SYN洪水) 是種典型的DoS (Denial of Service,拒絕服務) 攻擊。效果就是服務器TCP連接資源耗盡,停止響應正常的TCP連接請求。

說到原理,還得從TCP如何建立連接(Connection)講起。通信的雙方最少得經過3次成功的信息交換才能進入連接全開狀態(Full-Open),行話叫建立TCP連接的3次握手(TCP three-way handshake)。

本文假設連接發起方是A,連接接受方是B,即B在某個端口(Port)上監聽A發出的連接請求。如下圖所示,左邊是A,右邊是B。

正常的TCP三次握手,From Wikipedia

A首先發送SYN(Synchronization)消息給B,要求B做好接收數據的准備;B收到后反饋SYN-ACK(Synchronization-Acknowledgement) 消息給A,這個消息的目的有兩個:(1) 向A確認已做好接收數據的准備,(2) 同時要求A也做好接收數據的准備,此時B已向A確認好接收狀態,並等待A的確認,連接處於半開狀態(Half-Open),顧名思義只開了一半;A收到后再次發送ACK(Acknowledgement)消息給B,向B確認也做好了接收數據的准備,至此三次握手完成,“連接”就建立了,實際上只是雙方都按對方的要求進入了可以接收消息的狀態。以上彼此要求對方確認的“狀態”主要是雙方將要使用的消息序號(SequenceNum),TCP為保證消息按發送順序抵達接收方的上層應用,需要用消息序號來標記消息的發送先后順序的。TCP是“雙工”(Duplex)連接,同時支持雙向通信,也就是雙方同時可向對方發送消息,其中SYN和SYN-ACK消息開啟了A→B的單向通信通道(B獲知了A的消息序號);SYN-ACK和ACK消息開啟了B→A單向通信通道(A獲知了B的消息序號)。

以上討論的是在雙方誠實可信,網絡正常的理想狀況下建立連接。但實際情況是,網絡可能不穩定會丟包,使握手消息不能抵達對方,也可能是對方故意不按規矩來,故意延遲或不發送握手確認消息。假設B通過某TCP端口提供服務,B在收到A的SYN消息時,積極的反饋了SYN-ACK消息,使連接進入半開狀態,因為B不確定自己發給A的SYN-ACK消息或A反饋的ACK消息是否會丟在半路,所以會給每個待完成的半開連接都設一個Timer,如果超過時間還沒有收到A的ACK消息,則重新發送一次SYN-ACK消息給A,直到重試超過一定次數時才會放棄。

SYN Flooding, From Wikipedia

做好人是要付出代價的,B為幫助A能順利連接,需要分配內核資源維護半開連接,那么當B面臨海量的大忽悠A時[1],如上圖所示,SYN Flood攻擊就形成了。攻擊方A可以控制肉雞向B發送大量SYN消息但不響應ACK消息,或者干脆偽造SYN消息中的Source IP,使B反饋的SYN-ACK消息石沉大海[2],導致B被大量注定不能完成的半開連接占據,直到資源耗盡,停止響應正常的連接請求[3]

接下來說說應對思路。最簡單粗暴的辦法就是提高TCP端口連接容量的同時減少半開連接的資源占用時間。在Linux上可以修改以下配置提高TCP半開連接隊列大小的上限:

/proc/sys/net/ipv4/tcp_max_syn_backlog

可以減少半開狀態下等待ACK消息的時間或者重試發送SYN-ACK消息的次數:

/proc/sys/net/ipv4/tcp_synack_retries

抑或啟用某種半開連接回收機制,使得當半開連接隊列滿了以后做“除舊迎新”操作,當然並不是所有系統都支持這種機制。

以上方法更像是權宜之計,只是緩解了被攻擊時的系統壓力,以及稍稍提高了些防御門檻,但也同時影響了部分正常的請求的建立,比如減少SYN-ACK重試次數,同樣也會降低某些網絡環境不好的正常用戶的連接成功率;而且攻擊者只要稍稍改變策略就可以提高攻擊效果,比如當使用半開連接回收機制時,攻擊者只需提高攻擊頻率就可使大部分正常的等待的半開連接,在ACK消息到來前就被踢出隊列。

另一個思路是將攻擊扼殺在搖籃,比如部署支持“IP防偽”的路由器,將偽造過IP地址的SYN消息過濾掉,或是提高網民防護意識減小肉雞網絡的規模等,但這都太過理想,有些時候攻擊者都有高大上的背景,根本不需要攻擊前先抓肉雞,呵呵,你懂的☺。

以上兩個思路都沒有直擊症結所在--任何一個SYN消息無論來源是誰,都會消耗B的一些資源保存半開狀態,並逐漸達到“鳩占鵲巢”的效果。SYN Cache和SYN Cookies就是基於這個觀察提出的兩個方案。

SYN Cache的出發點主要是針對“鳩占鵲巢”問題,基本原理如下:構造一個全局的Hash Table,用來緩存系統當前所有的半開連接信息,連接成功則從Cache中清除相關信息;Hash Table中每個桶(bucket)的容量大小也有限制,當桶“滿”時做除舊迎新操作。當B收到一個SYN消息后,會將半開連接信息加入到Hash Table中,其中key的生成很關鍵,既要用到SYN消息中包含的信息(如:Source IP,Port等)又要做到很難被攻擊者猜到,一般會通過一個秘密的函數生成,這樣所有的半開連接無論好壞,都看似隨機地被平均分配到了不同的“桶”中,使攻擊難度大增,因為為達到DoS效果,攻擊者需要使每個桶都達到填滿狀態,並且還要有足夠快的“填桶”速度,使得正常的半開連接在還未完成建立前就被踢出桶,這樣的攻擊行為估計在達到目的前早就暴露了。

SYN Cookies着眼點主要是設法消除半開連接的資源消耗,原理與HTTP Cookies技術類似,B通過特定的算法把半開連接信息編碼成“Cookie”,用作B給A的消息編號(SequenceNum),隨SYN-ACK消息一同返回給連接發起方A,這樣在連接完全建立前B不保存任何信息。如果A是正常用戶,則會向B發送最后一次握手消息(ACK),B收到后驗證“Cookie”的內容並建立連接;如果A是攻擊者,則不會向B反饋ACK消息,B也沒任何損失,也就說是單純的SYN攻擊不會造成B的連接資源消耗。當然這種方案也有一定缺點,最明顯的就是B不保存連接的半開狀態,就喪失了重發SYN-ACK消息的能力,這一方面會降低正常用戶的連接成功率,另一方面會導致某些情況下正常通信的雙方會對連接是否成功打開產生誤解,如A發給B的第三次握手消息(ACK)半路遺失,A認為連接成功了,B認為沒收到ACK,連接沒成功,這種情況就需要上層應用采取策略特別處理了。

當然,所有這些方案都不完美各有利弊,最終的策略可能是幾種方案的結合使用,形成防御體系,將攻擊提前化解在局部,不至於影響整個系統。

[1] 實際攻擊時攻擊方不太會暴力的發送大量SYN消息,這樣反倒會提前暴露自己,而是先嗅探出被攻擊對象的TCP配置參數,如半連接狀態過期時間,隊列上限等,掌握好節奏更量體裁衣的發送攻擊消息,做到用最經濟最不易被發現的方式鳩占鵲巢,占滿半連接隊列。
[2] 偽造Source IP(IP Spoofing)有一定講究,不能選一個真實的有TCP連接能力的主機,因為TCP協議要求在收到莫名其妙的SYN-ACK消息時,直接返回RST消息,這反倒提示被攻擊的B可以提前中止假冒的半開連接,將其清理出隊列。
[3] 這里指特定端口(Port)的連接資源被耗盡不能接受新連接請求,端口上已經建立的連接和其他未被攻擊的端口不受影響。

本文原創,歡迎轉載,但請注明出處

參考資料:
https://en.wikipedia.org/wiki/SYN_flood
https://en.wikipedia.org/wiki/Transmission_Control_Protocol
https://tools.ietf.org/html/rfc4987
http://cr.yp.to/syncookies.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM