TCP可靠传输二探
1. 背景介绍
首先,我们来简单回顾一下,在《TCP可靠传输初探》中我们整体了解了TCP是怎样保证可靠传输的同时尽可能提升传输效率。第一、TCP通过确认机制、超时重传机制防止分组丢失以及丢失分组后重传;第二、通过纠错码编码技术检验和修正传输过程中造成的数据错误。第三、停止和等待 顺序传输方式存在效率低的问题,为此必须提高发送的并发度,但同时带来了首发两端速率不匹配的问题,因此TCP采用了滑动窗口控制发送端的发送速率;第四、提高了发送端发送速率同时也增加了网络的负担,TCP拥塞控制通过检测丢包率来判断网络的拥塞程度,及时踩刹车。总之,TCP通过确认机制、超时重传机制、纠错码技术、滑动窗口、拥塞控制保证了高可靠的网络数据传输。
1.1.TCP的头部结构
介绍TCP的可靠性保证机制前,我们有必要熟悉一下TCP的头部结构,了解各个字段区间存在的意义。如下图所示。
从头部结构,我们可以得到以下信息:
TCP的一个连接通过四元组标识,分别是源地址IP、源地址端口、目标地址IP、目标地址端口。Sequence Number是包的序号,用于给包分配序号、用来解决网络包乱序(reordering)问题,还可以用来识别包,判重。Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。Window又叫Advertised-Window,也就是著名的滑动窗口(Sliding Window),用于解决流控的。TCP Flag ,也就是包的类型,主要是用于操控TCP的状态机的。具体字段的取值如下图所示。
比如,从TCP Flags字段的取值我们可以找到常见的:SYN、FIN、ACK、PUSH等最常见到的TCP包类型。
2.TCP状态机与建连断连过程
TCP传输分成建立连接、数据传输、断开连接几个阶段,如下如所示。
我们从上图可以看到建立链接、数据传输、释放连接的过程,这几个过程伴随着TCP首发两端状态的变化,TCP状态图如下图所示。
咋一看,状态机也太复杂了,但如果按照TCP建连、端连按阶段来分,其实也不复杂。
2.1为什么建立连接要3次握手,断链接却需要4次挥手?
建链接的3次握手
主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的ISN(Inital Sequence Number,初始序列编号)——所以叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。其实建立连接也可以4次握手,但没必要,因为被动方发送ACK和SYN是可以合并的,完全没必要分开,所以是3次握手。
注:关于ISN的初始化。ISN是不能硬编码的,不然会出问题的——比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。全乱了。RFC793中说,ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始。这样,一个ISN的周期大约是4.55个小时。因为,我们假设我们的TCP Segment在网络上的存活时间不会超过MSL(Maximum Segment Lifetime ),所以,只要MSL的值小于4.55小时,那么,我们就不会重用到ISN。
这样做可以防止ISN重用,另外出于安全考虑,也不应该对ISN硬编码。
对于4次挥手:能不能是3次挥手呢?
答案是不能。在主动断连一方发送FIN报文后,接收方受到后并不会立即发送FIN + ACK而只能先发送ACK,这时因为被动方还需要等待应用层处理完毕,才会发送FIN,正是由于被动方FIN和ACK是分开的,且连接是全双工的,需要连接两段发别发送FIN且接收到ACK,所以这才产生了4次挥手。
2.2.建连接SYN超时怎样办?
试想一下,如果server端接到了client发的SYN后回了SYN-ACK后client掉线了,server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次(Ubuntu默认是6次,可通过cat /proc/sys/net/ipv4/tcp_synack_retries命令查询),重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会断开这个连接。
所以,当SYN超时时,未收到ACK一方会等待超时并重试,但这也给攻击者提供了可趁之机。
2.3.SYN Flood攻击
方法是给服务器发了一个SYN后,就下线了,于是服务器需要默认等63s才会断开连接,这样,攻击者就可以把服务器的syn连接的队列耗尽,让正常的连接请求不能处理。
应对策略:在Linux下给了一个叫tcp_syncookies的参数来应对这个事——当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie发回来,然后服务端可以通过cookie建连接(即使你不在SYN队列中)。请注意,请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为,synccookies是妥协版的TCP协议,并不严谨。对于正常的请求,你应该调整三个TCP参数可供你选择,第一个是:tcp_synack_retries 可以用他来减少重试次数;第二个是:tcp_max_syn_backlog,可以增大SYN连接数;第三个是:tcp_abort_on_overflow 处理不过来干脆就直接拒绝连接了。
以下是Ubuntu平台这几个参数的默认设置。
andy@andy:~/下载/a$ cat /proc/sys/net/ipv4/tcp_synack_retries5andy@andy:~/下载/a$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog 1024andy@andy:~/下载/a$ cat /proc/sys/net/ipv4/tcp_abort_on_overflow 0andy@andy:~/下载/a$ cat /proc/sys/net/ipv4/tcp_syncookies 1
fuck up是什么意思?
弄糟;毁坏
fuck up是什么意思
fuckup英[fʌkʌp]美[fʌkʌp]
[词典]弄糟,毁坏;
[例句]Ifuckupeverythingbutletmeexplain.
我搞砸了一切,但让我解释。
Linux 系统安全强化指南(建议收藏的教程)
本指南旨在说明怎样尽可能地加强Linux的安全性和隐私性,并且不限于任何特定的指南。
免责声明:如果您不确定自己在做什么,请不要尝试在本文中使用任何内容。
本指南仅关注安全性和隐私性,而不关注性能,可用性或其他内容。列出的所有命令都将需要root特权。以“$”符号开头的单词表示一个变量,不同终端之间可能会有所不同。
选择正确的Linux发行版
不使用与Systemd机制的发行版。Systemd包含许多不必要的攻击面;它尝试做的事情远远超出了必要,并且超出了初始化系统应做的事情。
使用musl作为默认的C库。Musl专注于最小化,这会导致很小的攻击面,而其他C库(例如glibc)过于复杂,容易产生漏洞。例如,与musl中的极少数漏洞相比,glibc中的一百多个漏洞已被公开披露。尽管仅靠披露的CVE本身通常是不准确的统计信息,但有时这种情况有时可以用来表示过分的问题。Musl还具有不错的漏洞利用缓解措施,尤其是其新的强化内存分配器。
最好默认情况下使用LibreSSL而不是OpenSSL的发行版。OpenSSL包含大量完全不必要的攻击面,并且遵循不良的安全做法。例如,它仍然保持OS/2和VMS支持这些已有数十年历史的古老操作系统。这些令人讨厌的安全做法导致了可怕的Heartbleed漏洞。LibreSSL是OpenBSD团队的OpenSSL分支,它采用了出色的编程实践并消除了很多攻击面。在LibreSSL成立的第一年内,它缓解了许多漏洞,其中包括一些高严重性的漏洞。
用作强化操作系统基础的最佳发行版是GentooLinux,因为它可以让您精确地配置系统,以达到理想的效果,这将非常有用,尤其是参考我们在后面的章节中使用更安全的编译标志。
但是,由于Gentoo的巨大可用性缺陷,它对于许多人来说可能并不顺手。在这种情况下,VoidLinux的Musl构建是一个很好的折衷方案。
内核
StablevsLTS内核
Sysctl
sysctl-w$tunable=$value
发表评论