本文漸進地介紹TCP
中的syn-cookie
技術,包括其由來、原理、實例測試。
TCP
鏈接創建時,客戶端經過發送SYN
報文發起向處於監聽狀態的服務器發起鏈接,服務器爲該鏈接分配必定的資源,併發送SYN+ACK
報文。對服務器來講,此時該鏈接的狀態稱爲半鏈接
(Half-Open
),而當其以後收到客戶端回覆的ACK
報文後,鏈接纔算創建完成。在這個過程當中,若是服務器一直沒有收到ACK
報文(好比在鏈路中丟失了),服務器會在超時後重傳SYN+ACK
。
若是通過屢次超時重傳後,尚未收到, 那麼服務器會回收資源並關閉半鏈接
,彷彿以前最初的SYN
報文歷來沒到過同樣!算法
這看上一切正常,可是若是有壞人故意大量不斷髮送僞造的SYN
報文,那麼服務器就會分配大量註定無用的資源,而且從backlog的意義 中可知,服務器能保存的半鏈接的數量是有限的!因此當服務器受到大量攻擊報文時,它就不能再接收正常的鏈接了。換句話說,它的服務再也不可用了!這就是SYN Flood
攻擊的原理,它是一種典型的DDoS
攻擊。segmentfault
Syn-Flood
攻擊成立的關鍵在於服務器資源是有限的,而服務器收到請求會分配資源。一般來講,服務器用這些資源保存這次請求的關鍵信息,包括請求的來源和目(五元組),以及TCP
選項,如最大報文段長度MSS
、時間戳timestamp
、選擇應答使能Sack
、窗口縮放因子Wscale
等等。當後續的ACK
報文到達,三次握手完成,新的鏈接建立,這些信息能夠會被複制到鏈接結構中,用來指導後續的報文收發。bash
那麼如今的問題就是服務器如何在不分配資源的狀況下服務器
ACK
的有效性,保證這是一次完整的握手SYN
報文中攜帶的TCP
選項信息SYN Cookies
算法wiki能夠解決上面的第1
個問題以及第2
個問題的一部分cookie
咱們知道,TCP
鏈接創建時,雙方的起始報文序號是能夠任意的。SYN cookies
利用這一點,按照如下規則構造初始序列號:併發
t
爲一個緩慢增加的時間戳(典型實現是每64s遞增一次)m
爲客戶端發送的SYN
報文中的MSS
選項值s
是鏈接的元組信息(源IP,目的IP,源端口,目的端口)和t
通過密碼學運算後的Hash
值,即s = hash(sip,dip,sport,dport,t)
,s
的結果取低 24 位則初始序列號n
爲:tcp
t mod 32
m
的編碼值s
當客戶端收到此SYN+ACK
報文後,根據TCP
標準,它會回覆ACK
報文,且報文中ack = n + 1
,那麼在服務器收到它時,將ack - 1
就能夠拿回當初發送的SYN+ACK
報文中的序號了!服務器巧妙地經過這種方式間接保存了一部分SYN
報文的信息。測試
接下來,服務器須要對ack - 1
這個序號進行檢查:編碼
t
與當前之間比較,看其到達地時間是否能接受。t
和鏈接元組從新計算s
,看是否和低 24 一致,若不一致,說明這個報文是被僞造的。mss
信息到此,鏈接就能夠順利創建了。spa
既然SYN Cookies
能夠減少資源分配環節,那爲何沒有被歸入TCP
標準呢?緣由是SYN Cookies
也是有代價的:
MSS
的編碼只有3位,所以最多隻能使用 8 種MSS
值SYN
報文中的其餘只在SYN
和SYN+ACK
中協商的選項,緣由是服務器沒有地方能夠保存這些選項,好比Wscale
和SACK
Linux
上的SYN Cookies
實現與wiki
中描述的算法在序號生成上有一些區別,其SYN+ACK
的序號經過下面的公式進行計算:
內核編譯須要打開 CONFIG_SYN_COOKIES
seq = hash(saddr, daddr, sport, dport, 0, 0) + req.th.seq + t << 24 + (hash(saddr, daddr, sport, dport, t, 1) + mss_ind) & 0x00FFFFFF
其中,req.th.seq
表示客戶端的SYN
報文中的序號,mss_ind
是客戶端通告的MSS
值得編碼,它的取值在比較新的內核中有 4 種(老的內核有 8 種), 分別對應如下 4 種值
static __u16 const msstab[] = { 536, 1300, 1440, /* 1440, 1452: PPPoE */ 1460, };
感興趣的能夠順着如下軌跡瀏覽調用順序
tcp_conn_request |-- cookie_init_sequence |-- cookie_v4_init_sequence |-- __cookie_v4_init_sequence |-- secure_tcp_syn_cookie
若是服務器和客戶端都打開了時間戳選項,那麼服務器能夠將客戶端在SYN
報文中攜帶了TCP
選項的使能狀況暫時保存在時間戳中。當前使用了低 6 位,分別保存Wscale
、SACK
和ECN
。
客戶端會在ACK
的TSecr
字段,把這些值帶回來。
Linux中的/proc/sys/net/ipv4/tcp_syncookies
是內核中的SYN Cookies
開關,0
表示關閉SYN Cookies
;1
表示在新鏈接壓力比較大時啓用SYN Cookies
,2
表示始終使用SYN Cookies
。
本實驗是在4.4.0
內核運行的,服務端監聽50001
端口,backlog
參數爲3
(該參數意義)。同時,模擬不一樣的客戶端注入SYN
報文。
echo 0 > /proc/sys/net/ipv4/tcp_syncookies
能夠看到,在收到3
個SYN
報文後,服務器再也不響應新的鏈接請求了,這也就是SYN-Flood
的攻擊方式。
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
因爲服務器的backlog
參數爲3
,所以圖中的從第4
個SYN+ACK
(#8報文)開始使用SYN Cookies
。
從時間戳能夠看出,#8報文(44167748)比 #6號報文(44167796)還要小。
44167748 = 0x2A1F244 ,最後低6位是 0b000100 ,與SYN報文中 wscale = 4 是相符的
SYN Cookie
技術可讓服務器在收到客戶端的SYN
報文時,不分配資源保存客戶端信息,而是將這些信息保存在SYN+ACK
的初始序號和時間戳中。對正常的鏈接,這些信息會隨着ACK
報文被帶回來。