TCP的FIN/RST Cookie

写在前面

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时间前还活着。当然,这个超时机制是可以优化的。

关于爱情简短的句子

TCP的FIN/RST Cookie

相关文章:

你感兴趣的文章:

标签云: