SSL/TSL
在双方通信之前,需要商量一个用于对称加密的密钥。我们知道网络通信的信道是不安全的,传输报文对任何人是可见的,密钥的交换肯定不能直接在网络信道中传输。因此,使用非对称加密,对对称加密的密钥进行加密,保护该密钥不在网络信道中被窃听。
⭐这样,通信双方只需要一次非对称加密,交换对称加密的密钥,在之后的信息通信中,使用绝对安全的密钥,对信息进行对称加密,即可保证传输消息的保密性
非对称加密
公钥只能加密,不能解密,私钥解密
甲对乙说,我这里有A型号锁,对应钥匙A,我给你一大箱子A锁(公钥),但是钥匙A(私钥)不给你,以后你给我发消息就用A锁锁在盒子里给我,然后我自己用钥匙A就能打开看。
- 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
- 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
对称加密
共享唯一密钥,可以加密也可以解密
甲对乙说,我这有一把锁,以后我们互相传消息,就把消息放盒子里,然后用这个锁锁上再传,这个锁有两把一模一样的钥匙,咱俩一人一把,说完甲把钥匙递给了乙。
证书颁发机构CA(身份验证)
客户端 C 和服务器 S 想要使用 SSL/TLS 通信,由上述 SSL/TLS 通信原理,在进行非对称加密之前,C 需要先知道 S 的公钥,而 S 公钥的唯一获取途径,就是把 S 公钥在网络信道中传输。要注意网络信道通信中有几个前提:
- 任何人都可以捕获通信包
- 通信包的保密性由发送者设计
- 保密算法设计方案默认为公开,而(解密)密钥默认是安全的
因此,假设 S 公钥不做加密,在信道中传输,那么很有可能存在一个攻击者 A,发送给 C 一个诈包(AS的公钥),假装是 S 公钥,其实是诱饵服务器 AS 的公钥。当 C 收获了 AS 的公钥(却以为是 S 的公钥),C 就会使用 AS 公钥对数据进行加密,并在公开信道传输,那么 A 将捕获这些加密包,用 AS 的私钥解密,就截获了 C 本要给 S 发送的内容,而 C 和 S 二人全然不知。
同样的,S 公钥即使做加密,也难以避免这种信任性问题,C 被 AS 拐跑了!
解决:
为了公钥传输的信赖性问题,第三方机构应运而生——证书颁发机构。CA 默认是受信任的第三方。CA 会给各个服务器颁发证书,证书存储在服务器上,并附有 CA 的电子签名。
当客户端(浏览器)向服务器发送 HTTPS 请求时,一定要先获取目标服务器的证书,并根据证书上的信息,检验证书的合法性。一旦客户端检测到证书非法,就会发生错误。
数字签名(防止篡改)
数字签名,是 CA 在给服务器颁发证书时,使用散列+加密的组合技术,在证书上盖个章,以此来提供验伪的功能,防止证书被伪造
文件 -散列-> 摘要 -加密-> 签名
⭐
三个重要信息:文件、公钥、签名
发送者通过 散列+私钥加密 对文件进行签名,再将文件、公钥、签名发送给客户端
防止文件被篡改?
将签名解密,原文哈希,然后对比两者
防止签名被篡改?
公钥私钥
防止收到攻击者的信息(文件、公钥和签名都是攻击者的)/ 防止公钥被篡改?
只需要证明公钥生成者的身份。CA给签名者生成了一个证书(包含其身份信息和公钥),签名者把该证书发送给客户端验证,客户端就可以通过证书知道公钥的拥有者了
防止证书被篡改?
CA使用自己的私钥对证书进行了签名,放到证书中,每个人的电脑里都安装了根证书(包含了CA及其公钥),这样公钥就保证了签名的安全性,进而保证了证书的安全性!!
- 混合加密的方式实现信息的机密性,解决了窃听的风险。
- 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的风险。
- 将服务器公钥放入到数字证书中,解决了冒充的风险。
tls加密数据的过程
- ClientHello
客户端 向 服务器 发起加密通信请求,也就是 ClientHello 请求。主要向服务器发送以下信息:
(1)客户端支持的 TLS 协议版本,如 TLS 1.2 版本。
(2)客户端生产的随机数(Client Random),后面用于生成「会话秘钥」条件之一。
(3)客户端支持的密码套件列表,如 RSA 加密算法。用于生成对话密钥
- SeverHello
服务器收到客户端请求后,发出响应,也就是 SeverHello。服务器回应的内容有如下内容:
(1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。
(2)服务器生产的随机数(Server Random),后面用于生产「会话秘钥」条件之一。
(3)确认的密码套件列表,如 RSA 加密算法。
(4)服务器的数字证书(包含服务器的公钥)
- 客户端回应
客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,验证服务器的数字证书的真实性。
如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
(1)一个随机数(pre-master key)。该随机数会被服务器公钥加密。
(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。
服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的 会话秘钥。
- 服务器的最后回应
服务器收到客户端的第三个随机数之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。
然后,向客户端发送最后的信息:
(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
校验CA证书过程
CA 签发证书的过程,如上图左边部分:
首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
TCP
三次握手
A:喂,听得到我吗?
B:我听得到你,你听得到我吗?
A:我也听得到你
为什么要三次握手?
- 三次握手才可以 阻止重复历史连接的初始化(主要原因)
客户端发送的旧 SYN
报文在网络中阻塞了,并且客户端宕机,重新发送新的SYN报文(序列号不同):
在两次握手的情况下,服务端在收到客户端的旧SYN报文之后就进入ESTABLISHD状态,没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费。
而三次握手的情况下,服务端在收到客户端的旧SYN报文之后进入SYN_RECV状态,并返回ACK报文,客户端发现跟自己的期望确认号不同,就会返回RST报文给服务端来终止本次连接,从而阻止了历史连接的初始化。
- 三次握手才可以 同步双方的初始序列号
初始序列号的作用:按序接收、防止重复接收
四次握手其实也能够可靠的同步双方的初始化序号,但由于 第二步和第三步可以优化成一步,所以就成了「三次握手」。
两次握手只保证了 一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。
- 三次握手才可以 避免资源浪费
如果客户端发送的 SYN
报文在网络中阻塞了,重复发多次 SYN
报文(序列号相同),那么服务端在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费
第一二三次握手丢失会发生什么
四次挥手
A:我说完了,你说完就挂电话吧!
B:好嘞…
B:……
B:我也说完了,可以挂电话了
A:好嘞,拜拜
为什么要四次挥手?
第一二三四次挥手丢失会发生什么?
为什么最后要等待才进入close状态 / 需要 TIME-WAIT 状态?
- 防止历史连接中的数据,被后面新建立的相同四元组的连接错误的接收;
2MSL
时长,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。比如如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 Fin报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个MSL。
- 保证「被动关闭连接」的一方,能被正确的关闭;
第四次挥手时,客户端发送给服务器的 ACK 有可能丢失,如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,如果客户端没有等待而是直接释放,那么就永远接收不到FIN,服务端也永远接收不到ACK,就无法释放
为什么是2MSL?
2MSL时长 这其实是相当于至少允许报文丢失一次。比如,若 ACK 在一个 MSL 内丢失,这样被动方重发的 FIN 会在第 2 个 MSL 内到达,TIME_WAIT 状态的连接可以应对。
为什么三次握手不用?
三次握手超时重传syn,不会断开连接
半连接队列和 SYN Flood 攻击
半连接队列 (SYN队列):服务端收到第一次握手后,会将 sock 加入到这个队列中,队列内的 sock都处于 SYN_RECV 状态
全连接队列 (ACCEPT队列):在服务端收到第三次握手后,会将半连接队列的 sock 取出,放到全连接队列中。队列里的 sock 都处于 ESTABLISHED 状态。
所谓SYN Flood攻击,可以简单理解为,攻击方模拟客户端疯狂发第一次握手请求过来,在服务端憨憨地回复第二次握手过去之后,客户端死活不发第三次握手过来,这样做,可以把服务端半连接队列打满,从而导致正常连接不能正常进来。
Socket连接
socket()
函数,创建Socket
bind()
函数,给 Socket 绑定一个 IP 地址和端口
listen()
函数,进行监听,可以通过netstat
命令查看对应的端口号是否有被监听
connect()
函数,发起连接(成功是在第二次握手)
accept()
函数,来从内核获取已经连接的客户端socket,如果没有客户端连接,则会阻塞等待客户端连接的到来(成功是在第三次握手)1.创建服务端 socket,bind 绑定端口、listen 监听端口
2.将服务端 socket 注册到 epoll
3.epoll_wait 等待连接(客户端socket)到来,连接到来时,调用 accpet 获取已连接的 socket
4.将已连接的 socket 注册到 epoll
5.epoll_wait 等待事件发生(读写)
6.对方连接关闭时,我方调用 close
TCP 是如何保证可靠性的
无差错、不重复、按序到达、不丢失
数据的破坏、丢包、重复以及分片顺序混乱
TCP 是通过序列号、确认应答、重传、连接管理以及窗口控制等机制实现可靠性传输的
连接管理,序列号/确认应答,重传,流量控制,拥塞控制
重传
超时重传、快速重传、SACK重传(选择性确认,已收到的数据的信息)
滑动窗口
确认应答模式效率低,所以引进滑动窗口
允许发送方连续发送多个数据段而不需要等待确认
流量控制
发送窗口:不可发送 | 可发送 已发送未确认 | 已发送已确认
接收窗口:不可接收 | 可接收 | 已接收
发送窗口会根据接收窗口动态调整,接收窗口会根据接收能力动态调整
拥塞控制
四个算法:
慢启动:TCP连接刚建立时,发送端会以指数增长的速度增加拥塞窗口,避免一开始就发送过多数据导致网络拥塞。
拥塞避免:一旦拥塞窗口达到一定阈值(慢启动阈值),TCP会进入拥塞避免阶段。在拥塞避免阶段,拥塞窗口以线性增长的方式增加
拥塞发生:超时重传 ssthresh->cwnd/2,cwnd->1,进入慢启动
快速重传 ssthresh=cwnd/2,cwnd=cwnd/2,进入快恢复算法
快速恢复:快速重传和快速恢复算法一般同时使用,cwnd = ssthresh + 3(之前收到3个重复ACK(一个数据包到达 即离开网络,就会发送一个ack),表示有3个老数据包离开网络)
① 如果再收到重复的 ACK: cwnd 增加 1;
② 如果收到新数据的 ACK: cwnd = ssthresh,线性增长,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;
NAT
如果一个组织内部新建了局域网,此IP地址只能用于局域网内的通信,不能直接连到互联网上,此类IP就是私有IP。
不同局域网内的私有IP地址可以重复
NAT 可以把 私有IP地址(局域网LAN)转换成公有IP地址,这样,在广域网WAN中,就只需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置,而连接到该LAN的主机使用私有IP地址而不需要公共IP地址
NAT 不光可以缓解 IPv4 地址资源短缺的问题,还可以隐藏内部网络的实际拓扑结构,使得外部网络无法直接访问内部网络中的设备,从而提高了内部网络的安全性。
ARP
解决了在局域网中将IP地址映射到MAC地址的问题
IP地址是逻辑地址,用于网络层,MAC地址是物理地址,用于数据链路层
HTTP
1.1
简单、灵活、广泛、长连接、管道传输
无状态、明文传输、头部无压缩、头部冗长、队头阻塞、请求应答
2.0
头部压缩(消除重复头)、二进制数据、并发传输(解决了应用层的队头阻塞,没有解决tcp层的)、服务器推送
基于Stream发送的,消息分割成一个或多个帧在流里面传输,每个stream都有一个ID标识,接收端会根据ID将接收到的帧有序重组成消息,因此不同的请求响应消息就可以在不同的stream中并发传输,并且多个流共用一条TCP连接
http1.1按照顺序处理请求(串行处理,会有队头阻塞问题),2.0请求和响应的帧可交错传输,不再依赖顺序,单个 TCP 连接上可并行处理多个请求和响应
http1.1:处理请求A时阻塞,会导致请求B无法处理
http2.0:处理请求A时阻塞,可以并行处理,因此请求B不会阻塞,前提是请求A已经到达了应用层,在应用层处理时才发生了阻塞。如果是在tcp层发生了丢包,会导致整个连接都阻塞
https://juejin.cn/post/7455603828139753512
- 流(Stream): 已经建立TCP连接上的双向字节流,可以承载一个或多个消息
- 消息(Message): 一个完整的HTTP请求或响应,由一个或多个帧组成。特定消息的帧在同一个流上发送,这意味着一个HTTP请求或响应只能在一个流上发送
- 每一个帧可看做是一个学生,流可以认为是组(流标识符为帧的属性值),一个班级(一个连接)内学生被分为若干个小组,每一个小组分配不同的具体任务(请求/响应消息)。
- HTTP/1.* 一次请求-响应,建立一个连接,用完关闭;每一个小组任务都需要建立一个班级,多个小组任务多个班级,1:1比例 ⚪ 一 o ⚪ 一 o ⚪一 o
- HTTP/1.1 Pipeling解决方式为,若干个小组任务排队串行化单线程处理,后面小组任务等待前面小组任务完成才能获得执行机会,一旦有任务处理超时等,后续任务只能被阻塞,毫无办法,也就是人们常说的线头阻塞 ⚪一 o o o
- HTTP/2 多个小组任务可同时并行(严格意义上是并发)在班级内执行。一旦某个小组任务耗时严重,但不会影响到其它小组任务正常执行 ⚪三 o o o
3.0
QUIC、无队头阻塞(当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响)、1/0 RTT连接建立时间(QUIC 内部包含了 TLS)、连接迁移(使用连接ID标记连接的两端,IP地址改变,可以很快复用连接)
IPv4和ipv6区别
1. ipv4协议的地址长度为32位(4字节),ipv6协议有128位(16字节),可以提供更多的地址
ipv4以二进制数表示,ipv6以十六进制表示
ipv4以8位为一组,用.隔开,ipv6以16位为一组,用:隔开
2. ipv6首部为固定长度40字节,去掉了校验和,更加简化,提高传输效率
3. ipv6自动配置地址,ipv4手动或DHCP配置