歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> TCP的FIN/RST Cookie

TCP的FIN/RST Cookie

日期:2017/2/28 14:32:45   编辑:Linux教程

寫在前面

TCP在網絡時代的古代被設計出來,在中世紀被大量鋪開,那是一個紳士的時代,幾乎不存在網絡安全問題。TCP的諸多問題都是時代的遺毒。現在時代變了,TCP/IP技術也不再由紳士們壟斷,任何小朋友都可以利用現代技術在古代的城堡上轟出一個口子,和保護文物不同,目前TCP依然在使用中,因此我們需要做的不是靠政策去保護,而是加固TCP!但是我並不對這種加固報有樂觀的態度,唐吉坷德穿的盔甲屬於重甲,擋得住矛卻擋不住火槍,真正需要的是進化,協議的進化。

在平時的工作和周末的探索中,我也一直在想如何能讓TCP更健壯,即不是那麼容易被干掉,說白了就是可以識別一個FIN或者RST包的發送是偽造的攻擊行為還是連接中的正常行為。借鑒SSL協議以及TCP本身的SYN cookie機制,我設想並初步實現了一個FIN/RST cookie,和以往的一貫的思路一樣,事後我要看看是不是已經有了更好的實現,發現了IETF已經解決了這個問題,叫做TCP Authentication option(RFC 5925),其總體思路和我的想法差不多,只是實現思路不同,以下是我和標准不同的地方:

1.我將一個TCP連接分為了控制通道和數據通道,並且只在控制通道上作Authentication,這樣可以大大提高效率;

2.我將Auth機制按照安全性需求的高低分了層次;

3.我在TCP狀態機內部又實現了一個Auth DH狀態機;

4.我由於太懶沒有實現用戶接口。

我的實現和RFC 5925相同的地方在於,它免除了好多既有的攻擊效果,代價就是降低了效率!諸如那些由於FIN/RST包而引入的技術全部都可以免去了,比如time-wait之類的。

一點評論

Fin Cookie?RST Cookie?確認沒有拼寫錯誤?是的,就是這兩個cookie!如果我不小心把SYN cookie寫成了FIN cookie,那麼在更正的時候怎麼也不至於改為RST cookie吧!說說什麼是FIN/RST cookie吧,它其實是我個人的一些想法,並不是什麼標准化的東西,如果RFC上能找到這個建議,我也不用寫這篇文章了,這個cookie是仿造SYN cookie做的,為TCP的斷開提供一種認證機制,即不能像往常那樣簡單地偽造一個窗口內的FIN或者RST就可以斷開一個健康的TCP連接,以及更難得的,舊的FIN把新的連接斷開等。我認為TCP的這個脆弱性原本不是它本身所造成的,而是TCP/IP網絡的設計原則造成的,武功再高也怕菜刀,再健康的人也抵不住暴力。正確的做法應該是為TCP營造一個良好的治安環境,而這正是網絡安全的范疇。然而偽造的FIN/RST 看起來或者真實地,它就是屬於一個它將要end掉的健康的TCP連接的,這就不是網絡安全的范疇了,正所謂清官難斷家務事啊!因此,正是TCP本身的機制造成了偽造如此簡單,事實上應該說,TCP本身就不是健康的,或者說不是健壯的。一個健康的TCP連接,聽起來更像是一個沒有並發症的癌症病人一樣。

原因

TCP的控制流缺乏認證機制,僅僅靠4-tuple將TCP數據包關聯到一個連接,然後靠序列號和窗口機制判斷是否接收並處理。TCP對待控制流和數據流的方式是一致的。TCP重要的控制流包括初始化連接的3次握手和斷開連接的4次揮手。這種缺乏認證的帶內控制通道導致一個TCP連接特別容易被劫持,劫持者只要滿足幾個很容易滿足的要求即可,包括序列號落在窗口內,4-tuple符合等,而隨著網絡越來越好,速度越來越快,TCP的窗口會越來越大,導致實現TCP劫持會越來越容易。

數據通道和控制通道

由於TCP實現的是帶內控制,就是說數據和控制都是附著在一個連接的,因此區分數據通道和控制通道的意義不是很大,但是按照網絡通信的慣例-嚴格區分控制平面/數據平面/管理平面,還是把帶有特殊TCP標志的TCP數據包看作是控制平面的包,而只有數據和ACK的看作是數據平面的包。

可以想見,數據通道的包我們不必理會,自有上層協議保證其安全性,我們關心的是控制通道的包。也許你會問,如果TCP連接僅僅數據通道被劫持,即攻擊者沒有劫持任何帶有標志位的數據包,僅僅在一邊等著,然後瞄准窗口中的某個位置,發送搗亂的數據,這樣豈不是真實的端主機就沒法發送數據了嗎?確實是,但是這不是TCP層面的問題,用戶socket發現數據遲遲發不到對端可以自行斷開連接,接下來,它可以嘗試躲到IP隧道裡面...數據通道的安全性總是可以通過上層協議或者動作來保證,比如可以使用SSL連接或者使用VPN隧道等。但是控制通道本身卻不能這麼做,因為很多的控制數據流是不會展現在上層的。

以RST為例,當TCP棧處理了RST之後,連接就拆除了,留給上層的只是一個錯誤碼,對於FIN來講也是這樣,即便是使用SSL,這些數據包也會使SSL連接斷開,總的原因有二:第一,用戶的應用直接和傳輸層接口,沒有自己的會話保持機制;第二,即便是socket和會話層接口,其VFS文件操作方式也不足以控制網絡這種很難映射到文件的IO類型。

引入一個cookie

一個cookie就像一個柔軟的墊片,任何攻擊都必須突破這個墊片,而這個墊片的破損就指示了攻擊已經發生這件令人遺憾的事,需要做的就是鋪好這個墊片,然後在關鍵操作前檢查這個墊片是否被破壞,該技術現在已經用於防止棧溢出,防止半連接Dos攻擊,SSL握手協議的Finished消息,關於這些技術就不再多說了。類似的,TCP在處理FIN/RST的時候也可以引入類似的機制,即只有保證這個cookie沒有被破壞才繼續處理,否則就認為是第三方偽造的攻擊包,需要注意的是,該cookie機制的引入並沒有對TCP標准協議頭進行任何更改,只是增加了一個選項以及在更嚴格的情形下,增加了一個處於TCP標准狀態機轉換之上的內部DH狀態機。

級別一:不安全的cookie

雖說是不安全的cookie,但是也是可以提供安全保護,最不安全是相對最安全來講的。該cookie是一個摘要值,計算方法如下:

value=摘要算法(client-ISN, server-ISN, 偽IP頭校驗和, FIN/RST包的SEQ, FIN包的ACK)

其中,除了最後的兩個字段,其它的字段在3次握手之後就保存在TCP連接的協議控制結構體中了,兩端的值無疑是一致的,在保存了這些值之後,為該TCP連接的協議控制結構設置一個標志,表明必須認證FIN和RST。在發送FIN的時候,將上述的value保存在option中,傳給對端,對端接收後,從本連接的協議控制結構體中取出前三個字段,從該packet中取出後兩個字段,按照同樣的算法計算value2,比較value和value2,若不同,則不觸發FIN/RST序列,若相同,進入標准處理流程。

說一下關於RST的處理,本cookie機制僅僅針對處在ESTABLISHED狀態的TCP連接,如果3次握手還沒有完成,則對RST包進行正常處理。這就需要在兩端同時引入一個timeout機制,在一端的ESTABLISHED狀態的TCP連接進程crash掉之後,,在該timeout時限尚未過期時,保存TCP的的兩個方向的ISN以及偽IP頭的校驗和等字段,超時後,進入標准的RST處理模式,重要的是,應該在每收到一個ACK時,重置該定時器,說明對端還活著,起碼在RTT時間前還活著。當然,這個超時機制是可以優化的。

說它不安全意思是說,如果嗅探者嗅探到了3次握手的過程,那麼攻擊照樣可以進行。另外,針對摘要算法的偽IP頭參數,也有爭議,因為它會影響NAT設備的實現,因此這個字段不要也罷,畢竟能猜出兩個ISN的幾率很小。

級別二:安全的cookie

如果說級別一的cookie是增加了攻擊的難度的話,那麼級別二的cookie就完全保證了安全,因為它是依靠自身加密機制保證的。誠然,需要協商一個密鑰,還需要明確該密鑰用來加密什麼東西,剩下的問題就是實現問題了。如果說被攻擊者嗅探到ISN是一件很可怕的事的話,那麼引入一個字段,該字段從來不再網絡上明文傳輸,然後基於該字段做摘要,那不就解決問題了?PPP的CHAP就是基於這種思想設計的。目的很明確,其中一個比較簡單的實現還是認證一個value:

value=摘要算法(對端的random, 本端的random, 其它任何你想引入的...)

現在的問題是兩個random如何從本端傳給對端呢?答案當然是加密傳輸,密鑰是什麼?可選方案當然是自動協商,用DH?可以!那麼DH協商過程如何和TCP兼容?答案就是將其藏在TCP的option中,和TCP的SYN握手一起發起的,還可以有一個DH過程,或者復雜的其它密鑰協商過程,這些過程也可以不和SYN一起發起,甚至可以在任何時候重新發起,TCP標准的3次握手完成之後,上述的額外的協商可以繼續,它不會對TCP標准的狀態機轉換過程有任何影響,只是額外疊加了一個狀態機在option裡面。事實上,以DH為例,完全可以在SYN和SYN/ACK中2次握手完成。

關於RFC 5925

我的實現當然沒有RFC 5925那麼完備。要知道設計一個協議或者僅僅一個協議元素是一件很難的事情,你要考慮到的事情不知一面。通常人們喜歡固化一些東西以免除自動化帶來的困惑,然而這是不符合Internet設計原則的,固化的東西其適應性是非常有限的,充其量在你自己的環境中性能良好,可以不是一個普遍化的東西。我這裡實現的這個FIN/RST cookie就是固化的東西。

關於TCP/IP與進化

傳統TCP/IP-肉身必然是沉重的

神一樣的存在必然希望擺脫沉重的肉身!然而恰恰是這個沉重的肉身卻是一切的基礎。崇尚SDN的同時也隱約感覺到網絡的君主時代已經快要來臨,SDN就像路易十四那樣將眾人玩弄於股掌。君主時代的專制阻礙著進化的發生,進化是逐步的修補,是帶著沉重肉身的痛苦蹒跚。

控制平面必須和數據平面呆在一起,以人體為例,我們的內髒占據了大量的空間,其工作消耗著大量的能量,這個肉身是沉重的,但是就算是最偉大的人也不能奢望一個僅有的大腦存在,如果說思想是精化,那麼所有的內髒,包括大腦本身都是沉重的,都是負擔,我們要吃飯,要睡覺,要做太多的維護工作,全部都是為了所謂的思想,但是將內髒,大腦獨立於思想之外,類似SDN那樣卻是萬萬不能的。

然而,控制平面和數據平面的一體化確實限制了單個個體的規模,導致必須鋪開來很多個體,通過協作的方式擴大規模。以摩天大樓為例,真正的摩天大樓是不可能存在的,因為電梯會占據大量的空間。樓越高,電梯空間越大,因為每增加一層的高度,底層就要擴大一定的電梯空間,最終的摩天大樓會變成金字塔型的,低下無限大,頂上無限高。也許自然界的高山最能說明問題,群山總是能帶來美感,瘦而不豺,高而不愣。

Copyright © Linux教程網 All Rights Reserved