一、OSI七层模型
OSI(Open System Interconnection) 是理想化的模型,将网络进行分层,其目的是将复杂的流程简单化,每一层都完成自己的事情,从而实现分而治之(专人干专事)。
1. 网络分层的含义
下层是为上层提供服务的。分层如下:
- 应用层
-
- 应用层:用户最终使用的接口 微信、qq、网页等
-
- 表示层:怎么去把数据进行描述、压缩
-
- 回话层:建立会话和管理会话的
-
-
- 传输层:把数据传递给对方,怎么传,丢啦要不要重新传递
-
- 网络层:网络层就是寻址
- 网络接口层
- 6. 数据链路层:主要关心的是将两个设备连接起来连接数据
-
- 物理层:只关心如何传输数据, 传输的是0/1的比特流
=> 合并表示为四层:应用层、传输层、网络层、网络接口层
- 物理层:只关心如何传输数据, 传输的是0/1的比特流
=> 合并表示为四层:应用层、传输层、网络层、网络接口层
- 报文:引用层 + 数据
- 数据段:传输层 + 数据 + 端口号
- 数据包:网络层 + 数据 + 端口号 + ip地址
- 数据帧:链路层 + 数据 + 端口号 + ip地址 + mac地址
2. 地址
通讯是通过ip地址查找对应的mac来进行通讯的。IP地址是可变的(类似我们收件地址) MAC地址是不可变的。
- IP地址
- IPV4: IP地址的第四个版本,最大值为42亿个
- IPV6: aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa
- ip地址不是固定的
- MAC地址
- MAC地址原则是是唯一的,每一个网卡都会有一个mac地址
3. 物理设备
- 物理层
- 常见设备:光纤、同轴电缆、网线、中继器(局域网)
- 物理层就是只关心怎么传输的,比较傻,通过多口的中继器/集线器给连接在这个局域网中的所以设备广播数据消息,不安全
- 数据链路层
- 常见设备:交换机(局域网)
- 交换机会记录每个端口连接的设备的mac地址,通讯时通过这个mac地址直接找到对应的设备,而不是广播的方式。
- 网络层
- 常见设备:路由器(广域网)冲当网关
- 默认两个不同的网络,是不能相互通讯的,想让两个不同的区域的设备通讯,需要经历网关。
- 路由器相比交换机,有wan口就可以充当网关进行上网,没有wan口的路由器可以看成是交换机。
4. TCP/IP参考模型
- 什么是协议?
- 协议就是约定的规范(在7层模型中只有三层以上的才能称之为协议)
- 协议分类:
- 应用层协议:HTTP协议、DNS协议、DHCP协议
- 传输层协议:TCP协议、UDP协议
- 网络层协议:IP协议、ARP协议
- ARP协议
- 地址转换协议,核心价值在于将IP地址转化为mac地址
- 地址转换协议,核心价值在于将IP地址转化为mac地址
- DHCP协议
- 动态主机配置协议Dynamic Host Configuration Protocol
- 通过DHCP自动获取网络配置信息, 我们无需手动配置IP地址
- DNS协议 (应用层)
- DNS 是Domain Name System的缩写,DNS服务器进行域名和与之对应的IP地址转换的服务器
- DNS会对IP及域名进行缓存,采用的是udp(无连接)访问。
- 特征:
- DNS中保存着一张域名于对应的ip地址的表
- 一个域名对应一个IP地址。一个IP地址可以对应多个域名
- gTLD: generic Top-Level DNS Server 顶级域名服务器 为所有 .com、.net......后缀做顶级域名解析的服务器
- 域名层级:
- 顶级域名:.cn、
- 二级域名:.com.cn
- 三级域名:www.zf.com.cn 有多少个点,就是多少级域名
- 访问过程:当访问zf.com.cn
- 操作系统里会对DNS解析结果做缓存,如果缓存中有就直接返回IP地址
- 查找C:\WINDOWS\system32\drivers\etc\hosts,如果有就直接返沪IP地址
- 没有就通过DNS服务器查找离自己最近的根服务器,通过根服务器找到.cn服务器,将ip返回给DNS服务器
- DNS服务器会继续向此IP发送请求,去查找对应.cn下.com对应的IP...
- 获取最终的ip地址,缓存到DNS服务器上
5. TCP和UDP
这两个协议都在传输层,常说的TCP是面向连接的,而UDP是面向无连接的。
-
TCP
- tcp 传输控制协议(Transimision Control Protocal)可靠、面向连接的协议,传输效率低(在不可靠的IP层上建立可靠的传输层)。TCP提供全双工服务,即数据可在同一时间双向传播。
- TCP数据格式
- 源端口号、目标端口号,分别指代的是发送方随机端口、目标端对应的端口
- 序列号:32位序列号是用于对数据包进行标记、方便重组
- 4位首部长度:单位是字节,4位最大能表示15,所以头部长度最大位60
- URG:紧急信号
- ACK:确认信号
- PSH:应该从TCP缓冲区读走数据
- RST:断开重新连接
- SYN:建立连接
- FIN:表示要断开连接
- 窗口大小:当前网络通畅时将这个窗口值变大加快传输速度,当网络不稳定时减少这个值。在tcp中起到流量控制作用。
- 检验和:用来做差错控制,看传输的报文段是否损坏
- 紧急指针:用来发送紧急数据使用
- 注意:TCP对数据进行分段打包传输,对每个数据包编号控制顺序
-
TCP抓包
- client.js
const net = require('net'); const socket = new net.Socket(); socket.connect(8080, 'localhost'); // 客户端连接8080的服务端端口 socket.on('connect', function(data){ socket.write('connect server') socket.end() }); socket.on('data', function(data){ console.log(data.toString()) }); socket.on('error', function(error){ console.log(error) }); - server.js
const net = require('net'); const server = net.createServer(function(socket){ socket.on('data', function(data){ socket.write('server:hello') }); socket.on('end', function(data){ console.log('客户端关闭') }); }); socket.on('error', function(error){ console.log(error) }); socket.listen(8080) // 服务端启动监听8080端口 - 三次握手
- 我能主动和你打电话吗? SYN
- 当然可以啊!那我也能给你打电话吧? ACK、SYN
- 可以的呢,建立连接成功 ACK
- 三次握手是由于TCP是全双工的通讯服务,需要双方都确定可以相互发送和请求数据;
- 第二次握手,将请求连接的应答和确认双向通讯的连接建立一次发送回去;
- 数据传输
- 四次挥手
- 我要挂掉电话了哈? FIN
- 好的,我知道了 ACK
- 传输完之前正在传输的数据,然后通知,数据传输完毕,可以关闭连接了 FIN
- ok,断开连接 ACK
- 这里的中间两次挥不能合并为一次,是因为在当时可能还有之前的数据没有传输完毕,所有必能直接通知关闭连接,需要等确认数据传输完毕之后再通知关闭连接
- 为了防止最后的ACK丢失,发送ACK后需要等待一段时间,因为如果丢包了服务端需要重新发送FIN包,如果客户端已经closed,那么服务端会将结果解析成错误。从而在高并发非长连接的场景下会有大量端口被占用。
- client.js
-
UDP
- udp用户数据报文协议(User Datagram Protocol,是一个无连接、不保证可靠性的传输层协议)。
- UDP发出请求后,不考虑对方是否能接收到、内容是否完整、顺序是否正确。收到数据后也不会进行通知
- 首部结构简单,在数据传输时能实现最小的开销
- 使用场景:DHCP协议、DNS协议、QUIC协议等(处理速度快,可以丢包的情况)
- TCP数据格式:
-
UDP抓包
- client.js
const dgram = require('dgram'); const socket = dgram.createSocket('udp4'); socket.on('message', function(msg, rinfo){ console.log(msg.toString()) console.log(rinfo) }); socket.send(Buffer.from('hello world'), 0, 5, 41234, 'localhost', function(err, bytes){ console.log('发送啦%d个字节', bytes) }); socket.on('error', function(error){ console.log(error) }); - server.js
const dgram = require('dgram'); const socket = dgram.createSocket('udp4'); socket.on('message', function(msg, rinfo){ console.log(msg.toString()) console.log(rinfo) console.send(msg, 0, msg.length, rinfo.port, rinfo.address) }); socket.bind(41234, 'localhost')
- client.js
-
滑动窗口
- 滑动窗口:TCP是全双工的,所以发送端有发送端缓存区,接收端有接收端缓存区,要发送的数据都放到发送中的缓存区,发送窗口(要被发送的数据)就是要发送缓存中的哪一部分数据。
- 核心是流量控制:在建立连接时,接收端会告诉发送端自己的窗口大小(rwnd),每次接收端收到数据后都会再次确认(rwnd)大小,如果值为0,停止发送数据。(并发送窗口探测包,持续监测窗口大小) 控制发送方的频率
- 发送数据的时候时乱序发送的,但是当我们收到某个包后,坑你之前的包还没有收到,此时需要等待前面序号的包到了才可以(对头阻塞)
- 服务端会和客户端说明发送包的个数
- 如果某个包丢了,那需要重新发送(超时重传 RTO)
- 当接受方的缓存区收满了,整滑动窗口大小为0,不发生数据,然后会每间隔一段时间,发送方会发送一个探测包,来询问能否调整滑动窗口大小。或者是上层协议消耗掉了接受放的数据,接受方的缓存区有空闲了,接收方也会主动通知发送方调整窗口,继续发送数据。
-
粘包算法
- nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段(TCP内部控制)
- Cork算法:当达到MSS(Maximum Segment Size)值时统一进行发送(此值就是帧的大小 - ip头 - tcp头=1460个字节)理论值
-
TCP用塞处理
假设接受窗口大小是无限的,接受到数据后就能发送ack包,那么传输数据主要依赖于网络带宽,带宽的大小是有限的- tcp常见的阻塞问题
- 队头阻塞:TCP顺序问题,后面的包先到达需要等待前面的包返回之后才可以继续传输
- 非长连接的情况下会有大量端口被占用:time-wait 客户端连接服务器最后不会立即断开,在高并发的短链接情况下,会出现端口全部专用。
- 慢启动过程,非常的消耗性能
- 拥塞处理:TCP维护一个拥塞窗口cwnd(congestion window)变量,在传输过程中没有阻塞就将此值增大。如果出现拥塞RTO(Retransmission Timeout)就将窗口减少
- cwnd < ssthresh 使用慢开始算法
- cwnd > ssthresh 使用拥塞避免算法
- ROT时更新ssthresh值为当前窗口的一半,跟新cwnd = 1
w
- 传输轮次:RTT(Round-trip Time) 从发送到确认信号的时间
- cwnd控制发送窗口的大小
- 快重传快恢复方式
- 快重传,可能在发送的过程中出现丢包情况,此时不要立即回退到慢开始阶段,而是对已经收到的报文重复确认,如果确认次数达到3次,则立即进行快重传快恢复算法(减少超时重传机制的出现),降低重置cwnd的频率。
- tcp常见的阻塞问题
二、HTTP发展历程
- 1990年HTTP/0.9为了便于服务器和客户端处理,采用来纯文本格式,只能使用GET请求。在响应请求之后会立即关闭连接
- 1996年HTTP/1.0增强来0.9版本,引入了HTTP Header(头部)的概念,传输的数据不再仅限于文本,可以解析图片音乐等,增加了响应状态码和POST,HEAD等请求方法
- 1999年广泛使用HTTP/1.1,正式标准,允许持久连接,允许响应数据分块,增加了缓存管理和控制,增加了PUT、DELETE等新的方法 (多个请求并发,管线化,http队头阻塞的问题)
- 2015年HTTP/2,使用HPACK算法压缩头部,减少数据传输量。允许服务器主动向客户端推送数据,二进制协议可发起多个请求,使用时需要对请求加密通讯。(多路复用 1条tcp连接来通信数据)
- 2018年HTTP/3基于UDP的QUIC协议
1. HTTP/1.1
HTTP是基于tcp传输层,半双工通讯的请求应答模式。http默认是无状态的(默认tcp是不能在没有应答完成后复用tcp通道继续发送消息,)。
-
tcp规范就是固定的组成结构
- 请求行 响应行:主要的目的就是描述要做什么事,服务端告诉客户端OK来
- 请求头 响应头:描述传输的数据内容,自定义我们的header(http中自己所做的规范)
- 请求体 响应体:两者间传输的数据
-
内容协商
客户端和服务端进行协商处理,返回对应的结果。 -
长连接
TCP的连接和关闭,需要经历三次握手四次挥手等过程,非常耗时间,所以我们可以复用TCP创建的连接。在http/1.1中实现了长连接,会默认在请求和响应头中增加Connection:keep-alive/Connection:close。但是复用同一个tcp通道必须在一个请求响应结束之后,才能执行下一个请求操作,这就形成了阻塞,就是http/1.1中的对头阻塞,需要采用管线化的方式解决这个问题。 -
管线化
如果只创建一条TCP连接来进行数据的收发,就会变成“串行”模式,如果某个请求过慢就会发生阻塞问题(队头阻塞 Head-of-line blocking)。HTTP/1.1中采用来管线化的方式,对一个域名同时发起多个长连接实现并发。默认chrome为6个。 -
Cookie
Set-Cookie/Cookie用户第一次访问服务器的时候,服务器会写入身份标识,下次再请求的时候会自动携带cookie。通过Cookie可以实现有状态的回话。(通常Cookie不要过大) -
HTTP缓存
- 强缓存:服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。
就是当客户端第一次访问服务端后,服务器说,在几点之前/多久之内 不要来找服务器了,直接在客户端的缓存中读取数据即可(在几点之前/多久之内不会再向服务器发送请求)。
Expires(http/1.0版本过时的参数,针对不支持http/1.1的服务做兼容方案)Cache-Control: max-age=300(缓存的最大有效时间)
强制缓存存在有效期,缓存期内不会向服务器发送请求,超过时间后需要取服务端严重是否是最新版本。
- 协商缓存:就是当强制缓存失效后会再次向服务器发起请求,服务器需要对比客户端的缓存的文件和服务器端端文件是否一致,如果一致则返回304状态码,如果文件更新了,就返回最新的文件数据。
- 最后修改时间:
last-modified/if-Modified-Since在于以下两种情况下存在问题:- 最后修改时间是秒级的,一秒内修改多次无法监控
- 最后修改时间变动了,但是内容没有发生变化
- 指纹标识:
Etag/If-None-Match- 摘要算法 md5 (不同的内容摘要的结果肯定不同,两个相同的内容摘要的结果肯定相同,无法通过最终的结果反推原内容,并且摘要的结果长度相同)。所以可以使用
Etag/If-None-Match,如果签名一致则认为文件没有变化,可以使用缓存。 Cache-Control: no-chche(不缓存,但是缓存中有,每次都询问服务器,相当于跳过了协商缓存);Cache-Control: no-stare(真正的不缓存,压根就没有缓存)。- 当数据较大的时候,md5生产指纹比较消耗性能,会简单的使用弱指纹,可以用
last-modified+文件长度,生产一个Etag指纹标识。
- 摘要算法 md5 (不同的内容摘要的结果肯定不同,两个相同的内容摘要的结果肯定相同,无法通过最终的结果反推原内容,并且摘要的结果长度相同)。所以可以使用
- 最后修改时间:
- 强缓存:服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。
2. HTTP/2
- 多路复用
- 头部压缩
- 服务端推送
3. HTTP/3
- QUIC协议
三、HTTP中的优化
1. Timing
2. 优化
3. CDN
四、web安全之HTTPS
HTTP采用明文传输,中间人可以获取到明文数据(从而实现对数据的篡改)。这时候HTTPS就派上用场了。HTTPS是什么呢?HTTPS=HTTP+SSL/TLS,SSL是安全套接层(Secure Sokkets Layer)发展到V3时改名为TLS(传输层安全 Transport Layer Security),主要目的是提供数据的完整性和安全性,保证数据秘文传输并不会被篡改。
1. 数据完整性
- 摘要算法
- 把任意长度的数据压缩成固定的长度
- 输入不同输出的结果发送剧烈的变化“雪崩效应”,相同的内容摘要后结果相同
- 不能从结果反推输入
我们可以在内容后面增加hash值进行传输,服务端收到后通过hash值来校验内容是否完整。数据是明文的不安全。
2. 数据加密
-
对称加密
加密和解密时使用的密钥都是同一个,通讯过程使用密匙加密后的密文传输。只有自己和网站才能揭秘目前AES(Advanced Encryption Standard)、chacha20 为最常见大对称加密算法。
唯一的密钥在传输的过程中可能会被中间人劫持而存在安全风险,不能确定这个公钥是谁发的。 -
非对称加密(安全但是性能不好)
非对称加密可以解决“密钥交换”的问题。非对称加密有两个密钥,公钥、私钥,所以称之为非对称。公钥加密私钥解密。 使用两套钥匙实现加密通讯,安全性高,但是性能不好,效率低,数据越大解密越复杂。最常听到的非对称加密算法是RSA、ECC(子算法ECDHE用于密匙交换,ECDSA用于数字签名)(性能和安全略胜一筹)HTTPS中目前广泛使用ECC
-
混合加密
通讯刚开始的时候使用非对称算法,交换密钥。在客户端生成会话密钥后传送给服务端,后续通讯采用对称加密的方式这里还并不安全,还涉及到中间人攻击(指攻击者与通讯的两端分别建立独立的联系,并交换其收到的数据)
-
数字证书和CA
因为谁都可以发布公钥,所以我们需要验证对方身份。防止中间人攻击客户端会判断有效期、颁发者、证书是否被修改及证书是否被吊销。每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证。
- 加密:对传输的数据进行加密
- 数据一致性:保证传输过程中数据不会被篡改
- 身份认证:确认对方的真实身份
3. HTTPS过程解析
- 第一阶段
- 客户端会发送 handshake Prootocol: client hello
- Cipher Suites 密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法 (套件列表)
- Random 客户端随机数
- Version:TLS 1.2
- 服务端会发送 handshake Prootocol: server hello
- Version:TLS 1.2
- Random 客户端随机数
- Cipher Suites: 选择的套件
双方选择TLS版本,确定加密算法,生产两个随机数
- 客户端会发送 handshake Prootocol: client hello
- 第二阶段
- 服务端发送证书 certificate
- 服务端发送ECDHE参数,服务端Hello完成
- Server Key Exchange
- Server Hello Done
- 客户端发送ECDHE参数,以后使用密钥进行通讯吧,加密握手消息发送给对方
- Clent Key Exchange
- change Cipher Spec
- Encrypted HadnleShake Message
- 服务端发送会话凭证,以后使用密钥进行通讯吧,加密握手消息发送给对方
- new Session Ticket
- change Cipher Spec
- Encrypted HadnleShake Message