# 网络
# TCP三次握手
- 客户端发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,服务器由SYN=1知道客户端要求建立联机(客户端:我要连接你)
- 服务器收到请求后要确认联机信息,向A发送ack number=(客户端的seq+1),syn=1,ack=1,随机产生seq=7654321的包(服务器:好的,你来连吧)
- 客户端收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,客户端会再发送ack number=(服务器的seq+1),ack=1,服务器收到后确认seq值与ack=1则连接建立成功。(客户端:好的,我来了)
# TCP四次挥手
TCP是全双工信道,何为全双工就是客户端与服务端建立两条通道,通道1:客户端的输出连接服务端的输入;通道2:客户端的输入连接服务端的输出。两个通道可以同时工作:客户端向服务端发送信号的同时服务端也可以向客户端发送信号。所以关闭双通道的时候就是这样:
TIP
客户端:我要关闭输入通道了。
服务端:好的,你关闭吧,我这边也关闭这个通道。
服务端:我也要关闭输入通道了。
客户端:好的你关闭吧,我也把这个通道关闭。
挥手过程:
- Client向Server发送FIN包,表示Client主动要关闭连接,然后进入FIN_WAIT_1状态,等待Server返回ACK包。此后Client不能再向Server发送数据,但能读取数据。
- Server收到FIN包后向Client发送ACK包,然后进入CLOSE_WAIT状态,此后Server不能再读取数据,但可以继续向Client发送数据。
- Client收到Server返回的ACK包后进入FIN_WAIT_2状态,等待Server发送FIN包。
- Server完成数据的发送后,将FIN包发送给Client,然后进入LAST_ACK状态,等待Client返回ACK包,此后Server既不能读取数据,也不能发送数据。
- Client收到FIN包后向Server发送ACK包,然后进入TIME_WAIT状态,接着等待足够长的时间(2MSL)以确保Server接收到ACK包,最后回到CLOSED状态,释放网络资源。
- Server收到Client返回的ACK包后便回到CLOSED状态,释放网络资源。
# TCP和UDP的区别
# TCP 的队头阻塞
TCP 传输数据的时候,从一端发送给另外一端的数据会被拆分为一个个按照顺序排列的数据包,这些数据包通过网络传输到了接收端,接收端再按照顺序将这些数据包组合成原始数据,这样就完成了数据传输。
不过,如果在数据传输的过程中,有一个数据因为网络故障或者其他原因而丢包了,那么整个 TCP 的连接就会处于暂停状态,需要等待丢失的数据包被重新传输过来。
我们把在 TCP 传输过程中,由于单个数据包的丢失而造成的阻塞称为 TCP 上的队头阻塞。
# HTTP发展历程
- http 0.9 负责传输html,最早的时候没有请求头和响应头
- http 1.0 提供了http的header和状态码,根据header的不同来处理不同的资源
- http 1.1 默认开启了keep-alive连接复用,管线化支持同一域名最多6个请求
- http 2.0 一个域名一个tcp链接来发送数据(多路复用), 请求优先级, 头部压缩,服务器可以预推送数据(js、css等)给客户端
- http 3.0 解决了tcp的对头阻塞问题 QUIC 协议 采用了udp
# http/1.1
- HTTP/1.1 中增加了持久连接的方法,它的特点是在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持。
- HTTP/1.1 中试图通过管线化的技术来解决队头阻塞的问题。HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。
- 提供虚拟主机的支持。HTTP/1.1 的请求头中增加了 Host 字段,用来表示当前的域名地址,这样服务器就可以根据不同的 Host 值做不同的处理。
- 对动态生成的内容提供了完美支持。HTTP/1.1 通过引入 Chunk transfer 机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。
- HTTP/1.1 还引入了客户端 Cookie 机制和安全机制。
# HTTP/1.1 的主要问题
- TCP 的慢启动。一旦一个 TCP 连接建立之后,就进入了发送数据状态,刚开始 TCP 协议会采用一个非常慢的速度去发送数据,然后慢慢加快发送数据的速度,直到发送数据的速度达到一个理想状态,我们把这个过程称为慢启动。
- 同时开启了多条 TCP 连接,那么这些连接会竞争固定的带宽。
- 队头阻塞的问题。持久连接虽然能减少 TCP 的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次请求。如果 TCP 通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是著名的队头阻塞的问题。
# http/2 多路复用
在 HTTP/1 中,每次请求都会建立一次HTTP连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive ,解决了多次连接的问题,但是依然有两个效率上的问题:
- 串行的文件传输。当请求a文件时,b文件只能等待,等待a连接到服务器、服务器处理文件、服务器返回文件,这三个步骤。我们假设这三步用时都是1秒,那么a文件用时为3秒,b文件传输完成用时为6秒,依此类推。(注:此项计算有一个前提条件,就是浏览器和服务器是单通道传输)
- 连接数过多。我们假设Apache设置了最大并发数为300,因为浏览器限制,浏览器发起的最大请求数为6,也就是服务器能承载的最高并发为50,当第51个人访问时,就需要等待前面某个请求处理完成。
HTTP/2的多路复用就是为了解决上述的两个性能问题。 在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。 帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据 流。 多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
为什么HTTP1.1不能实现多路复用
HTTP/1.1 不是二进制传输,而是通过文本进行传输。由于没有流的概念,在使用并行传输(多路复用)传递数据时,接收端在接收到响应后,并不能区分多个响应分别对应的请求, 所以无法将多个响应的结果重新进行组装,也就实现不了多路复用。
# QUIC 协议
- 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
- 集成了 TLS 加密功能。目前 QUIC 使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。
- 实现了 HTTP/2 中的多路复用功能。和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
- 实现了快速握手功能。由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现使用 0-RTT 或者 1-RTT 来建立连接,这意味着 QUIC 可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。
# HTTPS
相比HTTP,HTTPS之所以更安全的是因为其在HTTP传输层之上加了一个安全层(SSL或TLS协议);HTTPS的安全性主要体现在下面3个方面:
- 数据的保密性(防窃听)
- 数据的完整性(防篡改)
- 通信双方身份的真实性(防冒充)
# 数据的保密性
要实现数据的保密,就需要使用加密算法对数据进行加密;HTTPS的加密方案就是:
- 连接建立过程:
- 客户端向服务器请求(发送TLS版本号、支持的加密算法、随机数C);
- 服务器返回非对称加密的公钥(证书)、商定的加密算法、随机数S给客户端;
- 客户端验证服务器返回的证书;
- 证书验证通过,客户端就根据服务器返回的证书及随机数S和随机数C生成一个会话密钥(对称加密);
- 客户端用服务器返回的公钥(证书)对会话密钥进行非对称加密后传输给服务器;
- 服务器通过私钥解密得到会话密钥;
- 客户端和服务器互相传输加密的握手消息来验证安全通道是否已完成;
- 通信过程
- 客户端使用会话密钥对传输的数据进行对称加密传输给服务器;
- 服务器使用会话密钥对传输的数据进行解密;
- 服务器使用会话密钥对响应的数据进行对称加密传输给客户端;
- 客户端使用会话密钥对传输的数据进行解密;
总的来说就是:连接建立过程使用非对称加密,后续通信过程使用对称加密。
# 数据的完整性
数据的加密,有效保证了数据不被窃听(很难得到原始的数据),但传输的数据在传输过程中有可能被篡改或替换。 解决方案是进行数字签名:使用Hash算法将任意长度的字符串转化为固定长度的字符串,该过程不可逆,可用来作数据完整性校验;
数字签名的简要过程(服务器-->客户端为例,客户端-->服务器类似):
- 服务器使用Hash算法对数据提取定长摘要
- 服务器使用私钥对摘要进行加密,作为数字签名
- 服务器将数字签名连同加密的数据一同传输给客户端
- 客户端使用公钥对数字签名进行解密,得到摘要A
- 客户端对解密后的传输数据也使用Hash算法得到定长摘要B
- 对比摘要A和摘要B,如果不一致则数据已被篡改
# 通信双方身份的真实性
以上加密过程,最核心的就是非对称加密的公钥和私钥;如果这个密钥都是攻击者提供的,那传输的数据在攻击者那里也是相当于裸露的; 如何确保密钥是不被冒充的呢?HTTPS使用了数字证书(签名),数字证书就是身份认证机构CA(Certificate Authority)加在数字身份证上的一个签名, 证书的合法性可以向CA验证;证书的制作方法是公开的,任何人都可以自己制作证书,但只有权威的证书颁发机构的证书能通过CA认证;
数字证书主要包含以下信息:
- 证书颁发机构
- 证书颁发机构签名
- 证书绑定的服务器域名
- 证书版本、有效期
- 签名使用的加密算法(非对称算法,如RSA)
- 公钥
# Charles抓包原理
其实Charles做的就是针对HTTPS的通信双方身份的真实性进行处理;
- 当客户端和服务器建立连接时,Charles会拦截到服务器返回的证书(服务器公钥)
- 然后动态生成一张伪造证书(Charles公钥/假公钥)发送给客户端
- 客户端收到Charles证书后,进行验证;因为之前我们手机设置了信任,所以验证通过;(只要手机不信任这种证书,HTTPS还是能确保安全的)
- 客户端生成会话密钥,使用Charles证书对会话密钥进行加密再传输给服务器
- Charles拦截到客户端传输的数据,使用自己的Charles私钥进行解密得到会话密钥
- 连接成功后,客户端和服务器通信,客户端对传输的数据使用会话密钥加密并使用公钥对数据摘要进行数字签名,一同传输给服务器;
- Charles拦截到通信的数据,使用之前获得的会话密钥解密就能得到原始数据;
- Charles同样也能篡改通信的数据:将篡改后的数据重新加密并重新生成摘要并使用之前获得的公钥进行数字签名,替换原本的签名,再传输给服务器;
- 服务器收取到数据,按正常流程解密验证;
- 服务器返回响应数据时,Charles也是类似拦截过程
# 防抓包
抓包主要的原理就是中间人替换了原本的证书;防抓包就可以通过针对证书的校验来实现;
https不一定是安全的
https不一定全是安全的,一些网站会使用自签名证书。 自签SSL证书最容易被假冒和伪造,被欺诈网站利用;部署自签SSL证书的网站,浏览器会持续弹出警告;自签SSL证书最容易受到SSL中间人攻击。
# 参考
# JWT
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。
# JWT的构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload),第三部分是签证(signature).
# header
jwt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用HMAC或SHA256
# playload
载荷就是存放有效信息的地方,这些有效信息包含三个部分:
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明(建议但不强制使用):
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明: 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密。
公共的声明: 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
# signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
将这三部分用.连接成一个完整的字符串,构成了最终的jwt。