-
HTTP协议
- 一次http请求的过程
- 用户输入url,浏览器本地解析url,如果在host文件中存有对应ip则访问对应ip,否则将域名交给DNS服务器,DNS服务器返回对应IP地址,应用层向ip地址发送http请求,然后是传输层TCP的三次握手确认连接,第一次是客户端向服务器发送syn,第二次是服务器发送syn和ack到客户端,第三次是客户端发送syn与ack确认,此时TCP握手成功,然后到网络层,通过ARP协议,使用ip解析出MAC地址,然后通过MAC地址在数据链路层传输数据,服务器接收到数据包后,由web服务器处理该请求,查找客户端请求的资源,并返回响应报文。
- 断开连接需要TCP4次挥手,任意一方可开始,机器1发送fin=1到机器2表示数据传输完毕,断开请求,机器2返回ack=1确认收到关闭请求,等待机器2的信息传送完毕后,机器2发送fin=1到机器1,此时机器2会有定时器等待机器1返回ack=1,如果没有返回,会重发fin=1,机器1返回ack=1确认关闭请求。
- http与https的区别
- https需要去CA申请证书
- http运行在TCP之上,所有传输内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输内容都是加密的
- http默认端口80,HTTPS默认端口443
- GET和POST区别
- GET方法是从服务器获取资源
- POST方法是向指定URI提交数据,数据放在body中
- GET请求的URL有长度限制,而POST请求数据会放在消息体中,没有长度限制
- GET请求会被浏览器主动cache,而post不会
- GET请求在发送过程中产生一个TCP数据包,POST请求会产生两个数据包。对于GET请求,浏览器会将header和data一起发送,服务器返回响应,而POST请求,浏览器是先发送header,服务器响应100 continue,浏览器再发送data。
- 一次http请求的过程
-
TCP协议
- TCP三次握手与四次挥手,本文第一条
- 如何可以绕过三次握手?
- Linux3.7内核版本之后,提供了TCP Fast Open功能,可以减少TCP连接建立的时延
- 客户端发送 SYN 报文,该报文包含 Fast Open 选项,且该选项的 Cookie 为空,这表明客户端请求 Fast Open Cookie;
-
支持 TCP Fast Open 的服务器生成 Cookie,并将其置于 SYN-ACK 数据包中的 Fast Open 选项以发回客户端;
-
客户端收到 SYN-ACK 后,本地缓存 Fast Open 选项中的 Cookie。
- 所以第一次发起请求时,还是需要正常的三次握手,之后如果再次向服务器建立连接的过程:
- 客户端发送 SYN 报文,该报文包含「数据」(对于非 TFO 的普通 TCP 握手过程,SYN 报文中不包含「数据」)以及此前记录的 Cookie;
- 支持 TCP Fast Open 的服务器会对收到 Cookie 进行校验:如果 Cookie 有效,服务器将在 SYN-ACK 报文中对 SYN 和「数据」进行确认,服务器随后将「数据」递送至相应的应用程序;如果 Cookie 无效,服务器将丢弃 SYN 报文中包含的「数据」,且其随后发出的 SYN-ACK 报文将只确认 SYN 的对应序列号;
- 如果服务器接受了 SYN 报文中的「数据」,服务器可在握手完成之前发送「数据」,这就减少了握手带来的 1 个 RTT 的时间消耗;
- 客户端将发送 ACK 确认服务器发回的 SYN 以及「数据」,但如果客户端在初始的 SYN 报文中发送的「数据」没有被确认,则客户端将重新发送「数据」;
- 此后的 TCP 连接的数据传输过程和非 TFO 的正常情况一致
- 之后发起 HTTP GET 请求的时候,可以绕过三次握手,这就减少了握手带来的 1 个 RTT 的时间消耗
- /proc/sys/net/ipv4/tcp_fastopen
- 0 关闭
- 1 作为客户端使用 Fast Open 功能
- 2 作为服务端使用 Fast Open 功能
- 3 无论作为客户端还是服务器,都可以使用 Fast Open 功能
- Linux3.7内核版本之后,提供了TCP Fast Open功能,可以减少TCP连接建立的时延
- UDP与TCP的区别
- TCP半连接队列和全连接队列
- TCP三次握手的时候,Linux内核会维护两个队列:
- 半连接队列,也称SYN队列
- 全连接队列,也称accept队列
- 服务端收到客户端发起的SYN请求后,内核会把该连接存储到半连接队列,并向客户端返回ACK,服务端收到第三次握手的ACK后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到accept队列,等待进程调用accept函数时把连接取出来.
- 不管是半连接还是全连接队列,都有最大长度限制,超过限制时,内核会直接丢弃,或返回RST包
- 全连接队列:
- 查看TCP全连接队列的大小:服务端使用ss命令
- ss
- -l 显示正在监听(listening)的socket
- -n 不解析服务名称
- -t 只显示tcp socket
- 在LISTEN状态时(ss -lnt),Recv-Q/Send-Q表示的含义如下:
- Recv-Q:当前全连接队列的大小
- Send-Q:当前全连接最大队列长度
- 非LISTEN状态时(ss -nt)
- Recv-Q:已收到但未被应用进程读取的字节数
- Send-Q:已发送但未收到确认的字节数
- ss
- 当服务端并发处理大量请求时,如果TCP全连接队列过小,就容易溢出。发生了全连接队列溢出时,后续的请求就会被丢弃,出现服务端请求数量上不去的现象
- 丢弃连接是Linux的默认行为,我们可以选择向客户端发送RST复位报文,告诉客户端连接建立失败。
/proc/sys/net/ipv4/tcp_abort_on_overflow
这个文件默认为0- 0:表示如果全连接队列满了,就扔掉连接
- 1:表示如果全连接队列满了,就发送一个reset包给client,表示废除握手过程和连接
- 通常情况下,tcp_abort_on_overflow应该设置为0,更有利于应对突发流量
- 如何增大TCP全连接队列?
- TCP全连接队列最大值取决于somaxconn和backlog的最小值
- somaxconn 是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn 来设置其值;
- backlog 是 listen(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;
- nginx中backlog设置成5000的demo:
-
设置完后需要重启
- TCP全连接队列最大值取决于somaxconn和backlog的最小值
- 查看TCP全连接队列的大小:服务端使用ss命令
- 半连接队列:
- 服务端没有命令单独查看半连接队列,但可以抓住TCP半连接队列的特点,就是服务端处于SYN_RECV状态的TCP连接,就是在半连接队列中
- 因此,计算TCP半连接队列长度的命令如下:模拟半连接队列的溢出场景,实际上就是一直对服务端发送TCP SYN包,但是不回第三次握手的ACK,这样就会有大量的处于SYN_RECV状态的TCP连接,其实这就是所谓的SYN洪泛,SYN攻击,DDos攻击
- netstat -natp | grep SYN_RECV | wc -l
- 半连接队列的溢出处理是怎么做的?
- 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
- 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃
- 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;
- 半连接队列最大值
- 当 max_syn_backlog > min(somaxconn, backlog) 时, 半连接队列最大值 max_qlen_log = min(somaxconn, backlog) * 2;
- 当 max_syn_backlog < min(somaxconn, backlog) 时, 半连接队列最大值 max_qlen_log = max_syn_backlog * 2;
- syncookies
- 如果 SYN 半连接队列已满,开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接
- syncookies 是这么做的:服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,如下图所示。
-
syncookies 参数主要有以下三个值:
-
0 值,表示关闭该功能;
-
1 值,表示仅当 SYN 半连接队列放不下时,再启用它;
-
2 值,表示无条件开启功能;
-
- 因此,应对SYN攻击时,只需要设置为1即可
- 防御SYN攻击的方法:
- 增大半连接队列
- 通过源码得知,如果想增大半连接队列,不能单纯增加tcp_max_syn_backlog,还需一同增大somaxconn和backlog,也就是增大全连接队列,增大tcp_max_syn_backlog和somaxconn的方法就是修改Linux内核参数:路径分别为:/proc/sys/net/ipv4/tcp_max_syn_backlog
/proc/sys/net/core/somaxconn
- 通过源码得知,如果想增大半连接队列,不能单纯增加tcp_max_syn_backlog,还需一同增大somaxconn和backlog,也就是增大全连接队列,增大tcp_max_syn_backlog和somaxconn的方法就是修改Linux内核参数:路径分别为:/proc/sys/net/ipv4/tcp_max_syn_backlog
- 开启tcp_syncookies功能
- 路径为/proc/sys/net/ipv4/tcp_syncookies
- 减少SYN+ACK重传次数
- 当收到SYN攻击时,就会有大量处于SYN_RECV的TCP连接,服务端此时会重传SYN+ACK,当重传次数达到上限后,就会断开连接,因此,我们可以通过减少SYN+ACK的重传次数,加快连接断开来抵御攻击
- /proc/sys/net/ipv4/tcp_synack_retries
- 增大半连接队列
- TCP三次握手的时候,Linux内核会维护两个队列: