【Web协议详解与抓包实战】DNS、WebSocket、http2.0、TLS/SSL、TCP

本文深入讲解DNS解析机制,包括迭代查询和递归查询的区别,WebSocket的升级方式与工作原理,HTTP2.0的多路复用、服务器推送、二进制传输及标头压缩特性,TLS/SSL的安全握手流程与密钥交换机制,TCP的FastOpen优化和流控制策略。

DNS


当在浏览器输入域名www.baidu.com时,首先在浏览器缓存中查看是否有DNS记录,再在操作系统缓存中查找是否有DNS记录,如果都没,访问本地DNS服务器。
本地DNS服务器存在两种查询方式:迭代查询、递归查询

迭代查询:

本地DNS服务器将请求发给根域名服务器。根域名服务器返回顶级域名服务器.com的IP地址。
再由本地DNS服务器向顶级域名服务器.com发起请求,顶级域名服务器返回二级域名服务器的.baidu.com的IP地址。
再由本地DNS服务器向二级域名服务器.baidu发起请求,二级域名服务器返回权威域名服务器的www.baidu.com的IP地址。
本地DNS服务器得到www.baidu.com的IP地址,解析成功。

总结:发出请求,如果不能解决,就返回能解决的服务器IP地址,再向这个服务器发起请求。

递归查询:

本地DNS服务器将请求发给根域名服务器。
根域名服务器无法解析,根域名服务器向.com顶级域名服务器发起请求。
顶级域名服务器无法解析,顶级域名服务器向baidu.com二级域名服务器发起请求。
二级域名服务器无法解析,二级域名服务器向www.baidu.com权威域名服务器发起请求。
权威域名服务器解析成功,将结果一步一步返回,直到给本地DNS服务器。

总结:只发一次请求,要求对方给出最后结果,得不到结果自己去请求别的服务器。

websocket


升级方式:

客户端发送:
GET / HTTP1.1
Host:
Connection:keep-alive,Upgrade
Upgrade:websocket
Origin:。。。
Sec-websocket-key:

服务端返回:
HTTP/1.1 101 Web Socket Protocol Handshake
Connection:Upgrade
Upgrade:websocket
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:content-type
Access-Control-Allow-Origin:。。。
Sec-websocket-Accept://由Sec-websocket-key计算得到,提供基本防护

websocket复用了http的握手通道,客户端通过HTTP请求与WebSocket服务端协商升级协议。服务端返回101状态码,响应头显示Upgrade:websocket,协议升级完成后,后续的数据交换则遵照WebSocket的协议。

将消息拆分成一个或多个帧进行通信。帧中的FIN位为1时表示消息结束,FIN为0表示消息还未结束,后面还有帧。

websocket支持双向通信,服务端主动向客户端进行推送【之前使用AJAX轮询方式实现通知客户端更新】。现在客户端和服务器方都可以发送帧。客户端发送的帧要经过掩码处理,避免代理服务器缓存污染攻击。

websocket的长连接是基于ping(opcode=9)、pong(opcode=A)心跳帧【http1.1中的长连接是一个定时器,定时器到达后还没有请求过来就关闭长连接】,定时器达到后,发送一个pingpong心跳,如果心跳存在仍然保持联系。

在TCP协议关闭之前先关websocket,当服务器和客户端都发送且收到关闭帧(opcode=8)时,表示websocket通信关闭。

http2.0


  • 采用多路复用
  • 支持服务器消息推送
  • 使用二进制方式传输
  • 进行标头压缩,使传输数据量大幅减少。

浏览器规定HTTP2.0必须基于TLS/SSL。
h2:基于TLS协议运行的HTTP2.0
h2c:直接在tcp协议上运行的HTTP2.0

多路复用:

一条TCP连接上,可以存在多个处于open状态的stream流,实现并发。stream流上的streamID相同,说明是同一个数据流的帧。

服务器端推送:

当服务器返回客户端请求的资源时,会将再一次可能请求的资源通过push_promise帧,传给客户端放在缓存里。push_promise帧只能通过服务端发送。

二进制方式传输:

一条TCP连接上,可能有多个stream数据流。将消息拆分为帧。帧中以二进制压缩形式存放http/1的内容,在stream流上进行传输。同一条数据流【streamID相同的帧组成的一条数据流】中的帧有序,在接收时进行组装。

一条HTTP消息,可以由一个header帧【可能含有0个或多个持续帧】及0个或多个data帧组成,header帧里同时包含startline和header部分。
根据帧头type的不同,分为10种数据帧。有传递http包体、头部、指定stream流优先级、终止stream流、修改连接、修改stream流配置的不同类型帧。
客户端和服务端都可以创建且关闭帧。
为发送Header/Data消息而创建的数据流【由客户端发送】,streamID为135递增奇数;为push消息而创建的数据流【由服务端发送】,streamID为246递增的偶数。

标头使用HPACK算法进行压缩:

1、针对Header帧,使用静态表和动态表,对header name和value进行索引映射。
2、静态表是给出的61条规则的映射表,不在静态表中的header name和value可以使用ASCII码或Huffman编码。name和value使用哪种映射方法,编码方式,要不要存入动态表,是由header帧主体部分来决定。
3、可以将编码结果存入动态表中以后使用,动态表的大小可以由帧头为设置帧的settings_header_table-size来决定。

huffman编码:

出现概率较大的符号采用较短的编码,出现概率较小的符号采用较长的编码。

通过构建Huffman树,将概率从小到大排序。从出现概率最小的两个数开始,左节点为小数,右节点为大数。算出他们的父节点。再来一个概率,作为父节点的右节点,再得出一个父节点。直到所有的数都出现在huffman树中。左节点代表0,右节点为1,对每一个出现概率进行编码。
huffman构建树

总结:

http2.0中将http消息拆分成header帧和data帧。一条tcp连接上,可能有多个stream数据流,支持并发、多路复用。帧在数据流中可以进行双向传输,服务端发送的push_promise帧支持服务端推送。http2.0支持标头压缩,使用hpack算法,结合静态表动态表和huffman编码。

TLS/SSL


流程图:

TLS/SSL
1、client hello:客户端发起,与服务端进行协商。传递TLS版本,可选密码套件,生成随机数等信息。
2、server hello:服务器发起,确定TLS版本,密码套件,并生成随机数。
3、server Certificates:将CA颁布的数字证书发送给客户端,数字证书里包含用户等个人信息经过hash算法、CA机构私钥加密得到的密文。
4、ServerKeyExchange:根据选择的密钥交换算法传递参数。假设协商通过ECDHE算法的密钥,此时服务端提供ECC椭圆曲线参数以及P点,并且服务端生成的随机数私钥Ka,来生成Qa公钥【Qa=KaP】。将ECC椭圆曲线参数、P点、Qa公钥发送给客户端。
5、server hello done
6、客户端:
(1)客户端验明数字证书有效性。a、将证书中的个人信息提取出来,通过hash算法得到的D_cal,b、将密文使用CA机构的公钥进行解密得到D_pem。对比D_cal和D_pem,如果相等,说明认证成功。还要验证其他有效信息,例如域名/有效时间/是否吊销。
(2)ClientKeyExchange:客户端生成的随机数私钥Kb,与服务端传来的ECC椭圆曲线参数、P点进行计算,得到Qb【Qb=Kb
P】,将Qb公钥传给服务端。
(3)将服务端传来的Qa,与客户端自己生成的随机数私钥Kb相乘,生成pre-master密钥。
7、服务端:客户端传来的Qb与服务端自己生成的随机数私钥Ka相乘,也得到pre-master密钥。
此时,两方都已经有了pre-master密钥。将双方在握手阶段交换传递的随机数,与pre-master,利用伪随机函数得到最终密钥master-secret。
8、change_cipher_spec:客户端发送。客户端通知服务器后续的通信都采用协商的通信密钥和加密算法进行加密通信。

流程总结:

双方在握手期间协商密钥交换协议,服务端根据密钥交换协议生成公钥发送给客户端【一般采用的是ECDHE算法,服务端确定ECC椭圆曲线参数,和P点,随机生成私钥Ka,通过计算得到公钥Qa。将公钥Qa,椭圆参数,P发送给客户端】。并且发送CA签发的数字证书,该证书内容通过CA机构私钥加密。
客户端收到证书后先验明身份,使用CA机构公钥进行解密,判断是否与CA证书中个人信息经过hash加密后得到的结果是否相同。再验证域名有效时间是否吊销。验明身份后,通过服务端发送的椭圆参数、P,以及随机生成的私钥Kb,得到公钥Qb。将Qb公钥发送给服务端。
此时客户端和服务端都有了公钥,将公钥与两端随机生成的私钥相乘,得到pre-master,pre-master与握手阶段双方生成的随机数通过伪随机函数得到主密钥master-secret。
之后客户端和服务端的通信都是用主密钥进行对称加密【AES对称加密算法】

ECC算法原理:

ECC椭圆曲线中,(m+n=o)的含义为:两个点(m,n)两个点连成一条线与椭圆另一个交点关于x轴镜像的点(o)。即o的坐标可以通过m、n的坐标得到。当m,n为同一点P,则该直线就是P点的切线。
Qa=k*P=(P+P+P…+P),k个P进行相加。当已知k,P时,可以高效的计算的到Qa,但已知Qa,P,很难推断出k的值。保证了密钥生成过程中的安全性、高效性。

TLS1.3

TLS1.2在握手阶段,使用了一个RTT来协商使用哪个安全套件,造成不必要的延时,TLS1.2也存在着一些不安全的安全套件,很容易被破解。
TLS1.3提出只支持一些相对安全的安全套件,不在握手协商使用哪个安全套件,而是在第一次握手时就将所有支持的安全套件产生的公钥发送给服务端,服务端进行选择,然后产生对应的公钥。

对于握手的优化:
1、sessionID,第一次握手后生成密钥,服务端生成SessionID,对应密钥,传输SessionID给客户端。再之后的通讯过程中,客户端携带SessionID访问服务器,服务器从缓存或内存中得到对应的密钥,进行加密通讯。但是密钥是存在一个特定服务器的内存中,为了使集群服务器共享密钥,提出session ticket
2、根据集群共享的一个密码,对相关信息进行加密,发送给客户端。当客户端下次访问时,集群内服务器对密码进行解密,得到相应的密钥。
3、TLS1.3中的0RTT,也是在第二次请求之后,握手没有占用RTT。将密钥存在客户端和服务端,密钥还没有过期时,将加密信息发送给服务端,服务端进行解密。为了防止ORTT面对的重放攻击,即截获客户端发送的加密信息,一直访问服务器。所以需要对密钥进行过期时间设置。

BB84量子密钥分发:

使用到偏振光子的状态,使用不同的基对序列进行处理。
A产生一段随机数,使用客户端随机产生的基组对随机数进行处理,发送经过处理后发送给B。
B接收到光子后,不知道他是使用哪个基组进行处理的,也是随机选用一段基组,得到一组数据。
双方公开一段序列,这两组序列中,大概有百分之75的部分是相同的,对比相同的部分,就知道哪些位上的基猜测正确。A、B两方将所有序列的这些位上的数整理出来,就可以使用他们来作为密钥。
判断信息有没有被截取:如果被中间的E进行信息截取,他也需要猜测基组,猜对的可能为百分之75,75%*75%,B收到的序列,正确率为56%。双方在挑选出本来作为密钥的序列中挑选出来一部分进行公布,如果双方有很大差异,则说明信息被窃听,通信作废。

总结:

TSL首先要进行握手,客户端发送client hello,与服务端协商使用的TLS协议版本和密码套件,以及生成随机数。服务端接收到后确定这些参数,并生成随机数。服务端向客户端发送CA颁发的数字证书,证书里包含了网站等个人信息经过hash编码、CA机构私钥加密的密文。服务端也将根据协商的密码套件以及参数,例如ECDHE算法,得到私钥和公钥,将公钥发送给客户端。服务端发送hello done。客户端首先验明数字证书的有效性,和是否过期等,然后也生成私钥和公钥,公钥发送给服务端。此时客户端和服务端都有了对方的公钥,将对方的公钥和自己的私钥相乘,取x坐标,得到相同的pre-master。将pre-master和握手阶段两边生成的随机数通过为伪随机函数得到master-secret。之后客户端和服务端的通信都是通过主密钥进行对称加密。例如AES对称加密算法,将明文拆分成明文块,对每个明文块进行10轮加密,例如轮密钥加、字节替换、行移位、列混合等。再解密时,反过来操作。
TSL1.2使用一个RTT来协商使用哪个安全套件,造成不必要的时延,TSL1.3放弃一些现在不太安全的安全套件,在第一次通讯时,将所有密码套件的公钥发送给服务端,由服务端来选择,得到自己的公钥发送给客户端
sessionID和session ticket是对握手的优化,第一次握手得到密钥后,服务端保存,客户端下次访问时就可以直接取出密钥。

TCP


Fast Open TCP
Fast Open
可以降低TCP时延的Fast Open TCP连接过程:
第一次建立连接时,客户端发送初始序列号ISN,
服务端发送一个ACK还有自己的ISN,以及保存着协商后的TCP通讯参数的cookie。
客户端收到之后,保存cookie,向服务端发送ACK以及发起http请求。
第二次发起请求时,客户端就可以直接发送cookie、SYN、http请求,服务端通过cookie得到tcp通讯参数。大大提升了传输效率。

segment

为了防止IP层对数据分段,效率低,并且考虑到接收端的接收能力,TCP以段segment来发送数据。
序列号SYN的值是针对字节流,是为了解决字节流的可靠传输。
对字节流以MSS分割,需要考虑:
1、不含TCP头部20字节
2、要尽量大,又要防止被IP层MTU拆分,一般为536字节,因为MTU默认为576字节,减去IP头部20字节,TCP头部20字节。

流控制

发送端有发送窗口,接收端有接收窗口,发送端发送数据后,接收端会向发送端通知,自己可以接受的数据大小【接收窗口大小】,于是发送端就会发送不超过这个限度的数据。发送端发送窗口的起始位置取决的接收端返回的ACK序列号。
当接收端的应用层没有及时读取缓存中时,缓存区溢出,接收窗口变为0,窗口关闭不再进行数据传输。
发送端会发送一个仅含一个字节的窗口探测包,接收端会返回此时的接收窗口大小,如果窗口更新,则继续传输数据。

关闭连接

客户端发送FIN,服务端接收到之后返回ACK。服务端发送FIN,客户端接受到时候进入time_wait状态,客户端发送ACK后,两方都进入closed状态,连接关闭。

一般time_wait状态需要维持2MSL,以保证未发送到的所有报文失效。

keep_alive

对于长时间没有发送数据的长连接,需要关掉。先发送一个探测包,如果收到响应,说明tcp连接还是活跃的。如果没有收到,隔net.ipv4.tcp_keepalive_intvl=75时间内重发,可以发送net.ipv4.tcp_keepalive_probes=9次。

总结

tcp基于三次握手建立可靠连接,客户端发送初始序列号ISN,服务端返回ACK和自己的ISN。客户端再返回ACK,表示握手成功。为了降低TCP时延提出了fast open TCP连接,第一次通信时与三次握手过程相同,只是服务端会把此次通信协商好的tcp保存在cookie里发送给客户端,客户端下次请求时就可以直接带着cookie,发送他的SYN,http请求来实现通信。
tcp需要对传输的字节流以MSS为单位划分为segment。tcp使用窗口控制来提高速度,在收到确认应答时,将窗口滑动到确认应答的序列号位置。通过流控制实现发送端根据接收端的接收能力来控制发送的数据量。接收端向发送端发送自己的可以接受的数据大小,发送端就会发送小于等于这个限度的数据。当接收端的应用层没有及时读取缓存中的内容,接收端的可用窗口就会变成0。此时不能在进行数据传输。发送端会时不时的发送窗口探测,来检测接收端的窗口信息是否更新。
tcp为了防止网络拥塞,使用了拥塞控制,cubic是在丢包情况下进行拥塞控制,BBR依据探测带宽进行拥塞控制。
在通信开始时,使用慢启动,拥塞窗口以指数形式进行增长,当拥塞窗口达到慢启动阈值时,以线性方式增长,当产生丢包情况时,慢启动阈值设为当前拥塞窗口的一半,重新启动慢启动。当丢包不是很严重时,启动快速重传,当发送端收到三个重复的失序ACK时,就基于快速重传机制进行重发。快速重传这种丢包情况,可以采用快速恢复而不必重新进入慢启动。
当接收端发送三个重复的失序ACK时,使用SACK机制,不仅返回ACK,还返回SACK,包含乱序等信息,从而减少数据发送方重传的盲目性。
BBR算法:是在RTT开始增大,带宽维持一个恒定值时,就开始进行拥塞控制。开始是,发送速度以指数式增加,快速得到瓶颈带宽。到达瓶颈带宽时,排空网络缓存。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值