# Computer Network
# 0.网络层协议栈
协议层 | 描述 | 数据单位 | 协议举例 |
---|---|---|---|
应用层 | 提供各种网络应用 | 报文(message) | FTP、SFTP、SMTP、POP3、HTTP、DHCP、DNS |
传输层 | 在应用程序客户机和服务器之间提供传输服务 | 报文段(segment) | TCP、UDP |
网络层 | 主机和主机之间传输网络层分组 | 数据报(datagram) | IP、选路协议、ICMP |
链路层 | 在邻近单元之间传输分组 | 帧(frame) | ARP、信道划分协议(TDM、FDM、CDMA)、随机接入协议(CSMA/CD、ALOHA)、轮流协议(轮询协议、令牌传递协议) |
物理层 | 在节点之间传输比特流 | 比特流(bit) |
# 1. HTTP
# 1.1 HTTP 报文格式
# 1.1.1 HTTP 请求报文
GET /somedir/page.html HTTP/1.1 // 方法 对象URL路径名 版本
Host: www.someschool.edu // 服务器的域名(用于虚拟主机 ),以及服务器所监听的传输控制协议端口号。
// 如果所请求的端口是对应的服务的标准端口,则端口号可被省略。
Connection: close // 是否持久连接 or keep-alive
User-agent: Mozalla/5.0 // 浏览器类型
Accept: image/png // 浏览器支持的MIME类型(媒体类型)
Accept-language: fr // 返回对象的语言
Cache-Control: no-store // 指定请求和响应遵循的缓存机制
If-Modified-since: Sat, 29 Oct 1994 19:43:31 GMT // 对应返回的 Last-Modified
If-None-Match: "737060cd8c284d8af7ad3082f209582d" // 对应返回的 Etag
Cookie: name=range&&pwd=heyro // 之前服务器发送给浏览器的cookie
Referer: http://orange.com/dist // 表示浏览器所访问的前一个页面,正是那个页面上的某个链接将浏览器带到了当前所请求的这个页面。
Origin: http://orange.com // Referer 只保留了域名,详细的资源地址去掉了
# 1.1.2 HTTP 响应报文
HTTP/1.1 200 OK // 状态码和相应状态信息
Connection: keep-alive
Date: Tue, 09 Aug 2011 15:44:04 GMT // 服务器发送响应报文的时间
Server: Apache/2.2.3 (CentOS) // 服务器的名字
Content-Length: 6821
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache
Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
Expires: 2020.12.31 23:59:59 // 数据什么时候过期
Etag: "737060cd8c284d8af7ad3082f209582d" // 对于某个资源的某个特定版本的一个标识符,通常是一个 消息散列
# 1.1.3 Content-Type的几种常见类型:
- 其实也是POST常见的几种提交数据方式:
- text/html:HTML格式
- text/plain:纯文本格式
- image/png: 图片格式
- application/x-www-form-urlencoded:浏览器的原生form表单
- application/json:消息主体是序列化后的JSON字符串
- multipart/form-data:常见的POST数据提交方式
# 1.1.4 Cache-Control
- 该值是利用max-age判断缓存的生命周期,是以秒为单位,如何在生命周期时间内,则命中缓存。
- 请求指令:
- max-age(单位为s):指定设置缓存最大的有效时间,定义的是时间长短
- s-maxage(单位为s):同max-age,只用于共享缓存(比如CDN缓存)
- no-cache:每次访问资源,浏览器都要向服务器询问,如果文件没变化,服务器只告诉浏览器继续使用缓存(304)。
- no-store :绝对禁止缓存
- 响应指令:
- public :指定响应会被缓存,并且在多用户间共享。
- private :响应只作为私有的缓存,不能在用户间共享。
- no-cache:缓存前需要先向服务器验证是否缓存过期
- no-store:禁止缓存
- 请求指令:
# 1.1.5 状态码
100 Continue
200 OK
202 Accepted:服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。
301 Moved Permanently:被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。
302 Moved Temporarily:请求的资源现在临时从不同的URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
301比较常用的场景是使用域名跳转。302用来做临时跳转 比如未登陆的用户访问用户中心重定向到登录页面。
304 Not Modified:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。
400 Bad Request:客户端请求的语法错误,服务器无法理解。
401 Unauthorized:请求要求用户的身份认证。
403 Forbidden:服务器已经理解请求,但是拒绝执行它。
404 Not Found:请求失败,请求所希望得到的资源未被在服务器上发现。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
408 Request Timeout:请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。
502 Bad Gateway:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应
504 Gateway Timeout:作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。
区分408 & 504:
- 408:client <--> server,这两者之间,client没有在一定时间内完成请求的发送,server会催促一下。
- 504:client <--> proxy <--> server,proxy去请求上游的server的时候,没有得到及时的响应,于是proxy通知client 504.
# 1.2 HTTP 1.0 新特性
- 请求头和响应头,以 Key-Value 形式保存,协商了各种重要的信息:
- 请求头:
- 期望服务器返回的文件的类型
- 表示期望服务器采用的文件压缩方式
- 期望服务器返回的文件的编码方式
- 期望页面的优先语言
- 响应头:
- 服务器采用的压缩方法
- 服务器返回的文件类型
- 服务器返回的文件的编码方式
- 请求头:
- 状态码:请求的响应状态
- Cache机制:缓存已经下载过的数据,主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准
# 1.3 HTTP 1.1
# 1.3.1 HTTP 1.1 新特性
- 持久连接:一个TCP连接可以传输多个HTTP请求,根据浏览器的不同,同一个域名允许2-10个TCP连接
- 引入CDN:并同时为每个域名维护 6 个连接,这样就大大减轻了整个资源的下载时间
- 虚拟主机的支持:Host字段,用来表示当前的域名地址,一个服务器可以有一个IP、但多个域名。
- 支持动态生成的内容:Chunk transfer 机制,动态生成的内容未知大小,切分发送,最后用零长度为结尾,表示发送完毕。
- Cookie机制
- 缓存处理:引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match、Cache-Control等更多可供选择的缓存头来控制缓存策略。
# 1.3.2 HTTP 1.1 缺点
- TCP的慢启动:一种拥塞控制策略,在达到阈值之前,指数增加接收窗口的大小。
- 同时开启了多条 TCP 连接,这些连接会竞争固定的带宽。但图片可以后下载,CSS/JS要先下载,没区分优先级。
- 队头阻塞问题:多个请求公用一个 TCP 管道,在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态,因此数据不能并行请求。
# 1.4 HTTP 2.0
# 1.4.1 HTTP 2.0 解决的问题
- 解决慢启动和竞争带宽:一个域名只使用一个 TCP 长连接来传输数据,这样整个页面资源的下载过程只需要一次慢启动,且不会出现多个连接竞争带宽
- 解决队头阻塞:多路复用机制,客户端可以并发地发起多个请求,某个请求任务耗时严重,也不会影响到其他连接的正常执行。
# 1.4.2 HTTP 2.0 新特性
- 多路复用:
- 即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 对应一个 id ,这样一个连接上可以有多个 request ,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
- 添加了一个二进制分帧层,数据经过二进制分帧层处理之后,会被转换为一个个带有请求 ID 编号的帧,然后发送出去。
- 接收方收到不同 ID 的数据帧,然后将同一个 ID 的的数据帧合并在一起,对应某一个 request / 请求。
- 这样服务器就可以优先处理具有高优先级的请求,并且实现了资源的并行请求
- 资源并行请求,消除了HTTP 1.1的同一个管道中后面的任务会等待前面的任务(队头阻塞问题),但是由于 HTTP 2.0 对于一个域名只能使用一个长连接,在消除了带宽竞争问题的同时,又再次带来了队头阻塞——在一个连接中,一旦丢包,丢掉的包的后面的包就需要重传(考虑选择性重传与回退N帧)。
- 来自计算机网络-传输层的多路复用和多路分解的概念:
- 多路复用:从多个套接字收集数据, 用首部封装数据,然后将报文段传递到网络层。
- 多路分解:使用头部信息将接收到的数据段传递到正确的套接字。
- 二进制格式:HTTP 1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
- 可以设置请求的优先级:服务器接收到请求之后,会优先处理优先级高的请求。
- 头部压缩:HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送:服务器不需要客户端发起连接才能向客户端发送数据,服务器可以自主向浏览器/客户端推送数据。
- 比如,浏览器只请求了
index.html
,但是服务器把index.html
、style.css
、example.png
全部发送给浏览器。这样的话,只需要一轮 HTTP 通信,浏览器就得到了全部资源,提高了性能。 - 并且需要注意的是,这里的服务端推送其实并不能替代诸如websocket这样的技术,因为服务端推送是在浏览器层面,但是没有JavaScript API来获取这些推送事件的通知。
- 比如,浏览器只请求了
# 1.4.3 HTTP 2.0 的问题
- 队头阻塞: 对于某一个TCP连接而言,也就是回退N帧的情况。/ 还有一种是对于发送方的滑动窗口
- 区别于HTTP1.1的队头阻塞:
- HTTP1.1的队头阻塞是因为HTTP的机制,HTTP管道化,前面的请求没完成,后面的请求要等待。
- HTTP2.0的队头阻塞是因为TCP的机制,前面的数据包丢失了,后面的在回退N帧的情况下,即使客户端收到了也要发送方重传。更进一步的,在选择性重传的情况下,一旦超出了发送方维护的滑动窗口,也是需要重传的。
- 区别于HTTP1.1的队头阻塞:
- TCP三次握手,如果使用了HTTPS则还需要TLS的一次握手。
- TCP协议僵化:
- 网络上的中间设备(路由器、防火墙、NAT、交换机等)如果使用的旧TCP,遇到新的内容则无法识别,将会丢弃。但是要更新中间设备的TCP速度慢、代价大。
- TCP是通过操作系统内核来实现的,操作系统的更新滞后于TCP的更新。
- 综上二者很大程度阻碍了TCP的更新
# 1.5 HTTP 3.0(QUIC协议)
- 实现了类似 TCP 的流量控制、传输可靠性的功能。提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
- 集成了 TLS 加密功能,减少了握手所花费的 RTT 个数。
- 实现了 HTTP/2 中的多路复用功能。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
- 实现了快速握手功能。由于 QUIC 是基于 UDP 的, 可以实现使用 0-RTT 或者 1-RTT 来建立连接。
# 1.6 队头阻塞问题图示
HTTP 1.1:多个请求公用一个 TCP 管道,在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态,因此数据不能并行请求。
HTTP 2.0:由于TCP的机制,如果前面的数据包丢失了,后面的在回退N帧的情况下,即使客户端收到了也要发送方重传。更进一步的,在选择性重传的情况下,一旦超出了发送方维护的滑动窗口,也是需要重传的。
HTTP 3.0:解决了队头阻塞问题,在 HTTP 2.0 的基础上还实现了数据流的单独传输。
# 1.7 get和post的区别
角度 | get | post |
---|---|---|
请求 | 获取一个html页面/图片/css/js等资源 | 提交一个 |
缓存 | 请求结果可以作为缓存(上次没看完的视频,下次离线继续看) | 请求结果不能作为缓存(下单 -> post -> 返回的成功下单的页面) |
参数 | 请求数据在url的querystring里 | 请求的参数在http请求的body里 |
编码 | 只能进行URL编码,只能接收ASCII字符 | 无限制 |
请求次数 | 请求一次即可 | 优化时可以请求两次,第一次发送请求头,判断返回结果是否可以继续(100 Continue),第二次发送请求体。(被拒绝的情况下,可以少发一次请求体) |
幂等性 | 是 | 否,执行同样的操作,结果不一定相同 |
# 1.8 HTTP基本认证
- 概念:桌面应用程序也通过HTTP协议跟Web服务器交互, 桌面应用程序一般不会使用cookie, 而是把 "用户名+冒号+密码"用BASE64算法加密后的字符串放在http request 中的header Authorization中发送给服务端, 这种方式叫HTTP基本认证(Basic Authentication)
- 过程:
- 客户端发送http request 给服务器
- 因为request中没有包含Authorization header, 服务器会返回一个401 Unauthozied给客户端,并且在Response的 header "WWW-Authenticate" 中添加信息。
- 客户端把用户名和密码用BASE64加密后,放在Authorization header中发送给服务器, 认证成功。
- 服务器将Authorization header中的用户名密码取出,进行验证, 如果验证通过,将根据请求,发送资源给客户端
- 特点:
- 简单明了
- http协议是无状态的, 同一个客户端对 服务器的每个请求都要求认证。
- 扩展:什么是BASE64
- 一种基于64个可打印字符来表示二进制数据的方法。
- 是一个从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。
# 2. HTTPS
# 2.1 安全知识
# 2.1.1 数字签名
- 通常是为了验证身份和消息的完整性,假如客户端发送一封邮件,为了保证邮件的完整性,则需要通过私钥进行加密。
- 为了更加高效,采用对消息的哈希值进行私钥加密,生成的就是数字签名。
# 2.1.2 数字证书
有了数字签名,但是在传输过程中,公钥有可能被替换,因此需要一个第三方可信机构提供一个公钥,因此就有了数字证书。即公钥需要申请,并绑定到数字证书上。
# 2.2 SSL/TLS 构成
TLS:Transport Layer Security(其前身为 SSL:Secure Sockets Layer)
- 对称加密算法:AES、DES、RC4
- 非对称加密算法:RSA、ElGamal
- 散列算法:SHA1、MD5
# 2.3 SSL/TLS 目的
希望做到:加密、校验、证书
解决:窃听、无法认证、数据篡改
# 2.4 SSL/TLS 握手过程
- 客户端向服务器发出加密通信的请求,包括:
- 支持的协议版本:比如 TLS 1.0
- 客户端生成的随机数 client-random
- 支持的加密算法,比如RSA、DES等
- 服务器响应请求,包括:
- 确认使用的加密通信协议版本。
- 服务器生成的随机数 service-random
- 确认使用的对称密钥算法、非对称加密算法、MAC算法:
- 对称密钥算法适用于大量的数据传输,因此用于数据传输。
- 非对称加密算法用于用收到的服务器的CA中的公钥来加密PMS
- MAC算法(Message Authentication Code,消息认证码算法)用来在最后的时候,验证整个通信过程中数据没有被篡改
- 服务器的CA(Certificate Authority)证书(包含公钥)
- 客户端收到服务器的响应,验证服务器的证书:
- 证书是可信机构颁布(CA在证书上签名,CA数字签名)
- 证书处于有效期内,没有过期
- 证书的域名与服务器的域名一致
- 证书的使用方式与声明的策略和使用限制一致
- 客户端从证书中取出服务器的公钥,向服务器发送信息:
- 根据 client-random 和 service-random 计算出的一个新的随机数PMS(pre-master key,前主密钥)(第三个),该随机数用服务器的公钥加密,防止被窃听。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 如果服务器要求出示证书,则客户端会在这里发送自己的证书
- 可能是这样:其实在这一步对于客户端而言,握手就已经结束了,并且最后一步可能会发送MAC算法哈希得到的摘要(对应于下面第7步中所描述的)
- 服务器用自己的私钥解密,得到PMS。
- 至此,客户端和服务器都已经拥有了 PMS、client-random、service-random,使用这三者计算生成本次会话所用的主密钥MS(Master Secret)。
- 然后服务器和客户端分别向对方发送一个MAC算法生成的摘要,这一项是前面发送的所有内容的hash值,用来校验之前发送的消息是否被篡改了。
- 然后,向客户端最后发送下面信息:
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
# 2.5 HTTPS连接中接收/发送HTTP数据包会怎么样?
- 会怎么样:
- HTTPS会不高兴,浏览器也会不高兴。
- 阻止掉HTTP的AJAX请求,然后报一个Mixed Content的错误(黄色的警告)。
- 引入一个HTTP请求的 js 文件,会被浏览器直接 block 掉。
- 解决方案:
- 相对协议:将URL的协议(http、https)去掉,只保留
//
及后面的内容。比如<img src="//domain.com/img/logo.png">
- iframe:使用 iframe 的方式引入 http 资源
- 相对协议:将URL的协议(http、https)去掉,只保留
# 3. TCP协议
# 3.1 三次握手
- 第一次握手(SYN=1, seq=x):
- 客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
- 发送完毕后,客户端进入
SYN_SEND
状态。
- 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
- 服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。
- 发送完毕后,服务器端进入
SYN_RCVD
状态。 - 注意:
- 当一个 SYN 报文段到达的时候,服务器会检查处于 SYN_RCVD 状态的连接数目是否超过了 tcp_max_syn_backlog 这个参数,如果超过了,服务器就会拒绝连接。
- 服务器在回复 SYN-ACK 后,会等待客户端的 ACK ,如果一定时间内没有收到,认为是丢包了,就重发 SYN-ACK,重复几次后才会断开这个连接。这也是 SYN flood 攻击的来源。
- 第三次握手(ACK=1,ACKnum=y+1)
- 客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
- 发送完毕后,客户端进入
ESTABLISHED
状态,当服务器端接收到这个包时,也进入ESTABLISHED
状态,TCP 握手结束。
更进一步地:
- 如上图所示,这里有两个队列:syns queue(半连接队列);accept queue(全连接队列)。
- 三次握手中,在第一步server收到client的syn后,把这个连接信息放到半连接队列中,同时回复syn+ack给client(第二步);
- 第三步的时候server收到client的ack,如果这时全连接队列没满,那么从半连接队列拿出这个连接的信息放入到全连接队列中,否则按tcp_abort_on_overflow指示的执行。
- 这时如果全连接队列满了并且tcp_abort_on_overflow是0的话,server过一段时间再次发送syn+ack给client(也就是重新走握手的第二步),如果client超时等待比较短,client就很容易异常了。
- SYN flood攻击:
- syn flood 攻击就是针对的半连接队列的,攻击方不停地建立连接,但是建立连接的时候只做第一步,第二步中攻击方收到server的syn+ack后故意扔掉,导致server上的半连接队列满,其他正常请求无法加入队列中,从而停止服务。
- 防范手段:
- 增加积压队列:增加操作系统允许的可能半开连接的最大数量
- 回收最早的半开TCP连接:保证勉强能够服务新的连接请求
- 如果短时间内连续收到某个IP的重复SYN请求,ban掉该IP(之前做爬虫哈哈哈)
- SYN cookies:
- 在TCP服务器收到TCP SYN包并返回TCP SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP服务器在根据那个cookie值检查这个TCP ACK包的合法性。如果合法,再分配专门的数据区进行处理未来的TCP连接。(这里可能这个cookie是用服务器的私钥进行签名得到的)
- 缺陷:
- 服务器必须拒绝客户端
SYN
报文中的其他只在SYN
和SYN+ACK
中协商的选项,原因是服务器没有地方可以保存这些选项,比如大型窗口和时间戳 - 哈希加密运算耗时
- 服务器必须拒绝客户端
- 为什么不是两次握手?
- 表因:考虑这种情况,如果客户端的第一个SYN1在网络中滞留了,超时则会再发送一个SYN2,如果服务器回复了ACK2,建立了连接之后,又收到了滞留的SYN1,则会再回去ACK1,于是就建立了一个多余的连接,占用了不必要的网络带宽。
- 本质:网络上没有一个统一的全局时钟,两台机器分别为了确认序号,证明这个包是新的,而不是在链路中delay的。这就需要独一无二的 ISN(初始序列号)机制。
- 自己的理解:更进一步,所谓建立连接,并不是架起了一个实实在在的通道,而是对双方的时序、操作步骤等各方面通信中需要考虑的内容,达成了一致性。
- 为什么不是四次握手?
- 先这么写着
- 其实本身是四次握手的,客户端和服务器分别要对对方发送的SYN包回复ACK包,但是第二次握手和第三次握手都是服务器在发送数据:第二次是回复ACK,第三次是服务器发送SYN,因此可以将这两个过程合并为一次握手,减少通信次数
# 3.2 四次挥手
- 第一次挥手(FIN=1,seq=x)
- 假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
- 发送完毕后,客户端进入
FIN_WAIT_1
状态。
- 第二次挥手(ACK=1,ACKnum=x+1)
- 服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
- 发送完毕后,服务器端进入
CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入FIN_WAIT_2
状态,等待服务器端关闭连接。
- 第三次挥手(FIN=1,seq=y)
- 服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
- 发送完毕后,服务器端进入
LAST_ACK
状态,等待来自客户端的最后一个ACK。
- 第四次挥手(ACK=1,ACKnum=y+1)
- 客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入
TIME_WAIT
状态,等待可能出现的要求重传的 ACK 包。 - 服务器端接收到这个确认包之后,关闭连接,进入
CLOSED
状态。 - 客户端等待了2MSL( Maximum Segment Lifetime,最大段生命周期:指报文段在网络上存活/停留的最长时间)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入
CLOSED
状态。
- 客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入
- 为什么不是三次挥手?(合并第二次和第三次挥手):
- 在客服端第1次挥手时,服务端可能还在发送数据。所以第2次挥手和第3次挥手不能合并。
- 更详细的:
- 被动方此时有可能还有相应的数据报文需要发送,因此需要先发送ACK报文,告知主动方“我知道你想断开连接的请求了”。这样主动方便不会因为没有收到应答而继续发送断开连接的请求(即FIN报文)。
- 被动方在处理完数据报文后,便发送给主动方FIN报文;这样可以保证数据通信正常可靠地完成。发送完FIN报文后,被动方进入LAST_ACK阶段(超时等待)。
- TIME_WAIT:
- 概念:TCP 四次握手结束后,连接双方都不再交换消息,但主动关闭的一方保持这个连接2MSL。
- 解决的问题:
- 第四次挥手的 ACK 报文段不一定到达了服务器,为了不让服务器一直处于 LAST_ACK 状态(服务器会重发 FIN,直到收到 ACK),客户端还得等一会儿,看看是否需要重发。假如真的丢包了,服务器发送 FIN ,并且此时客户端的TCP连接还未关闭,还能够重新发送ACK。
- 假如客户端向服务器建立了新的连接,旧连接中某些延迟的数据坚持到了新连接建立完毕,而且序列号刚好还在滑动窗口内,服务器就误把它当成新连接的数据包接收。所以,经过 2MSL 之后,网络中与该连接相关的包都已经消失了,这样就避免了干扰新连接。
- 辨析
- MSL(Maximum Segment Lifetime):任何报文在网络上存活的最长时间。
- TTL(Time To Live):IP数据报头中的一个字段,由源主机设置初始值,存储了一个IP数据报可以经过的最大路由数,也就是,该IP数据报可以经过的最大跳数。
- RTT(Round-trip Time):一个传输层报文段从客户端到服务器往返所花时间,TCP含有动态估算RTT的算法,根据之前的估算值与真实值的差距,动态计算RTT:
- EstimatedRTT = (1- å) x EstimatedRTT + å x SampleRTT
- DevRTT = (1-ß) x DevRTT + ß * | SampleRTT - EstimatedRTT |
- TimeoutInterval = EstimatedRTT + 4 x DevRTT
- 其中,典型值:å = 0.125,ß = 0.25
- Dev RTT = Deviation RTT,DevRTT是SampleRTT和EstimatedRTT之差的指数加权移动平均,用于估算SampleRTT偏离EstimatedRTT的程度。
# 3.3 首部
TCP:20字节固定首部:
- 源端口
- 目的端口
- 序号:本报文段所发送的数据的第一个字节的序号
- 确认号:期望接收到的对方的下一个报文段的数据的第一个字节的序号
- 首部长度
- 检验和
- 标志位:
- URG:紧急数据,优先级高
- ACK:=1表示确认号字段有效
- RST:=1表示TCP连接中出现严重差错,必须释放重新建立连接
- SYN:=1表示同步,表示这是一个连接请求或者连接接受报文
- FIN:=1表示数据发送完毕,要求释放运输连接。
- PUSH:发送方接收到push指示后快速发送该数据及其之前的数据。
# 3.4 可靠数据传输机制
机制 | 用途和说明 |
---|---|
检验和 | 用于检测在一个传输分组中的比特错误。 |
定时器 | 用于检测超时/重传一个分组,可能因为该分组(或其ACK)在信道中丢失了。由于当一个分组被时延但未丢失(过早超时),或当一个分组已被接收方收到但从接收方到发送方的ACK丢失时,可能产生超时事件,所以接收方可能会收到一个分组的多个冗余拷贝。 |
序号 | 用于为从发送方流向接收方的数据分组按顺序编号。所接收分组的序号间的空隙可使该接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余拷贝。 |
确认 | 接收方用于告诉发送方一个分组或一组分组已被正确地接收到了。确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或累积的,这取决于协议。 |
否定确认 | 接收方用于告诉发送方某个分组未被正确地接收。否定确认报文通常携带着未被正确接收的分组的序号。 |
窗口、流水线 | 发送方也许被限制仅发送那些序号落在一个指定范围内的分组。通过允许一次发送多个分组但未被确认,发送方的利用率可在停等操作模式的基础上得到增加。我们很快将会看到,窗口长度可根据接收方接收和缓存报文的能力或网络中的拥塞程度,或两者情况来进行设置。 |
# 3.5 流量控制
- 原因:
- 接收方控制发送方,发送方不能发送太多、太快的数据让接收方缓冲区溢出
- 发送方的数据发送速度与接收方的应用程序的数据读取速度不匹配
- 类比:
- 高速缓存 => CPU指令执行速度 与 内存的访问速度不匹配
- 高速缓存(Cache)存在于主存与CPU之间的一级存储器,容量比较小但速度比主存高得多, 接近于CPU的速度。
- 文件缓冲区 => CPU速度 与 I/O设备的速度不匹配
- 文件缓冲区:用以暂时存放读写期间的文件数据而在内存区预留的一定空间。
- 解决:
- 接收方设置一个接收缓冲区 RcvBuffer,应用进程从接收缓冲区中读取数据
- 接收方通过在TCP头部中包含 rwnd 值,通告其接收缓冲区的剩余空间
# 3.6 拥塞控制
- 抑止发送方速率来防止过分占用网络资源
- 方法:
- 发送方增加传输速率(窗口大小),探测可用带宽,直到发生丢包:
- 加性增:每个RTT内,cwnd 线性(加性)增加1 MSS(最大报文段长度),直到检测到丢包
- 乘性减:发生丢包事件后(3个冗余ACK),cwnd减半
- 拥塞控制算法:
- 慢启动:当连接开始的时候,速率呈指数式上升(每次2倍),直到发生丢包 或者 到达阈值
- 拥塞避免:
- 在拥塞窗口 cwnd 增长到 ssthresh 之后,开始加性增
- 在超时发生时,ssthresh = cwnd / 2,cwnd = 1。
- 快重传:
- 要求接收方每收到一个失序的报文段后就立即发出重复确认
- 发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段。
- 快速恢复:
- 当发送端收到连续三个重复的确认时,把慢开始门限 ssthresh 减半,cwnd 设置为 ssthresh
- 然后进入加性增阶段
- 发送方增加传输速率(窗口大小),探测可用带宽,直到发生丢包:
# 3.7 TCP粘包
- 前置:
- TCP是基于字节流的传输层通信协议。TCP 传输的对象是「字节流」,流式传输,也就是一串连续的字节。问题在于流是没有边界的。对于TCP而言,没有“包”的概念只有“流”的概念。
- 粘包本质上应该是TCP数据序列化问题 / TCP数据的无边界性
- 原因:
- TCP连接复用:多个进程使用同一个TCP连接,不同的数据之间的边界分割因为流式传输而产生问题。
- TCP的Nagle算法(为了避免网络上出现很多的小数据包):
- 只有上一个分组得到确认,才会发送下一个分组
- 收集多个小分组,在一个确认到来时一起发送
- 多个分组拼装为一个数据段发送出去,如果没有好的边界处理,在解包的时候会发生粘包问题。
- 接收方应用程序没有及时接收缓冲区的包,造成多个包累积。
- 解决方法:(都只能是在应用层的)
- 使用带消息头的协议,在消息头中存储消息开始标识、消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。
- 设置定长消息,客户端每次发送定长的消息,当消息不够长时,空位填充固定字符。
- 设置消息边界,服务端从网络流中按消息编辑分离出消息内容,一般使用‘\n’。
# 3.8 TCP 快速打开(TCP Fast Open,TFO)
- 概念:
- 一般情况下,只有第三次握手才允许携带应用程序的数据
- TFO中,允许客户端在第一次握手的时候就携带数据,但是需要SYN包中的TFO cookie来通过验证,否则服务器将丢弃数据。
- 请求 Fast Open Cookie
- 客户端发送SYN数据包,该数据包包含Fast Open选项,且该选项的Cookie为空,这表明客户端请求Fast Open Cookie;
- 支持TCP Fast Open的服务器生成Cookie,并将其置于SYN-ACK数据包中的Fast Open选项以发回客户端;
- 客户端收到SYN-ACK后,缓存Fast Open选项中的Cookie。
- 实施 TCP Fast Open
- 客户端发送SYN数据包,该数据包包含数据(对于非TFO的普通TCP握手过程,SYN数据包中不包含数据)以及此前记录的Cookie;
- 支持TCP Fast Open的服务器会对收到Cookie进行校验:
- 如果Cookie有效,服务器将在SYN-ACK数据包中对SYN和数据进行确认(Acknowledgement),服务器随后将数据递送至相应的应用程序;
- 否则,服务器将丢弃SYN数据包中包含的数据,且其随后发出的SYN-ACK数据包将仅确认(Acknowledgement)SYN的对应序列号;
- 如果服务器接受了SYN数据包中的数据,服务器可在握手完成之前发送数据;
- 客户端将发送ACK确认服务器发回的SYN以及数据,但如果客户端在初始的SYN数据包中发送的数据未被确认,则客户端将重新发送数据;
- 此后的TCP连接和非TFO的正常情况一致。
# 4.RESTFUL
- 一种对互联网软件的架构原则
- REST = Representational State Transfer(表现层状态转换)
# 4.1 Representation
- "资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。
- 比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。
- URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。
# 4.2 State Transfer
- 访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
- 互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
- 客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
# 4.3 什么是RESTful架构
- 每一个URI(统一资源标识符)代表一种资源;
- 客户端和服务器之间,传递这种资源的某种表现层;
- 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。
- (用URL定位资源,用HTTP描述操作)
# 4.4 追加
- 解释:
- 看Url就知道要什么
- 看http method就知道干什么
- 看http status code就知道结果如何
- 核心思想是把「网页请求」当成「资源」(名词而不是动宾短语)来看待,以上三点都是为了实现如何把请求当成资源的
- 其他:URL定位资源,用HTTP动词(GET,POST,DELETE,PUT)描述操作。
# 5. Cookie & Session
# 5.1 Cookie
客户端请求服务器时,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。而客户端浏览器会把Cookie保存起来。当浏览器再请求 服务器时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器通过检查该Cookie来获取用户状态。
# 5.2 Session
当客户端请求创建一个session的时候,服务器会先检查这个客户端的请求里是否已包含了一个session标识 - sessionId,
- 如果已包含这个sessionId,则说明以前已经为此客户端创建过session,服务器就按照sessionId把这个session检索出来使用(如果检索不到,可能会新建一个)
- 如果客户端请求不包含sessionId,则为此客户端创建一个session并且生成一个与此session相关联的sessionId
sessionId的值一般是一个既不会重复,又不容易被仿造的字符串,这个sessionId将被在本次响应中返回给客户端保存。保存sessionId的方式大多情况下用的是cookie。
# 5.3 区别
- 存取方式不同,cookie只能保存ASCII的字符串,如果数据有二进制或者其它类型,需要进行编码,session乐意存取任何类型;
- cookie存储在客户端,对于客户端是可见的,一般大小限制在4k左右,session存储在服务器,不透明,更加安全;
- cookie支持跨域名访问,session只在它所在的域名有效;
- 因为session保存了用户所有的数据,所以占用内存大,不必每次发送请求都发送session给服务器,而是选择更轻量的cookie作为一种验证身份的标识发送给服务器。
# 5.4 token
- session:服务端存储的用户个人信息,用户登陆成功后返回一个sessionID
- cookie:每次发送请求的时候,都在cookie中带上sessionID
- token:
- 客户端通过用户名+密码登陆成功
- 服务端返回一个token
- 以后,客户端每次发送请求都要带上token
- 若服务端验证通过,才会处理请求
- 基于token的验证
- 基于Token的身份验证是无状态的,我们不将用户信息存在服务器中。这种概念解决了在服务端存储信息时的许多问题。
NoSession
意味着你的程序可以根据需要去增减机器,而不用去担心用户是否登录。 - 无状态、可扩展:在客户端存储的
Tokens
是无状态的,并且能够被扩展。基于这种无状态和不存储Session
信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。tokens
自己hold
住了用户的验证信息。 - 安全性:
- 请求中发送
token
而不再是发送cookie
能够防止CSRF
(跨站请求伪造)。即使在客户端使用cookie
存储token
,cookie
也仅仅是一个存储机制而不是用于认证。不将信息存储在Session
中,让我们少了对session
操作。 token
是有时效的,一段时间之后用户需要重新验证。
- 请求中发送
- 基于Token的身份验证是无状态的,我们不将用户信息存在服务器中。这种概念解决了在服务端存储信息时的许多问题。
# 6. DNS
作用:主机名 -> IP 地址的转换
# 6.1 域的划分
www.artrange.com(.root)
.root
所在位置:根域.com
所在位置:顶级域.artrange
所在位置:二级域www
所在位置:三级域
一些概念:
- 本地域名服务器:当一个主机发出DNS查询请求时,这个查询请求报文就发送给本地域名服务器,本地服务器替我们进行DNS解析,我们得到的ip地址是由本地域名服务器返回的。
- 根域名服务器:最大的
- 顶级域名服务器:com、org、net、edu等
- 权威域名服务器:是经过上一级授权,对域名进行解析的服务器,同时它可以把解析授权转授给其他人。
- hosts:在DNS系统之前,对应ip都是保存在hosts文件之中,现在系统仍然保留它。
# 6.2 DNS查询
递归查询:(“我不知道,我帮你问问我的领导/下属”)
- 主机 -> 本地域名服务器
- 本地域名服务器 -> 根域名服务器 -> 顶级域名服务器 -> 权威域名服务器
- 权威域名服务器 -> 顶级域名服务器 -> 根域名服务器 -> 本地域名服务器
- 本地域名服务器 -> 主机
迭代查询:(“我不知道,你自己去问那个谁(我的领导/下属)”)
- 主机 -> 本地域名服务器
- 本地域名服务器 -> 根域名服务器 -> 本地域名服务器
- 本地域名服务器 -> 顶级域名服务器 -> 本地域名服务器
- 本地域名服务器 -> 权威域名服务器 -> 本地域名服务器
- 本地域名服务器 -> 主机
# 7. UDP
# 7.1 主要特点
- 无连接的:发送数据之前不需要建立连接,减少了开销和发送数据之前的时延。
- 尽最大努力交付:不保证可靠的交付,主机不需要维持复杂的链接状态表。
- 面向报文的:
- 发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
- 接收方 UDP 对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文
- 没有拥塞控制。
- 单播、多播、广播,即支持一对一、多对一和多对多的交互通信。
- 首部开销小,只有8个字节。
# 7.2 首部(8字节)
- 源端口
- 目的端口
- 整个数据报文的长度(这个应该是数据的长度,不包括UDP的头部)
- 检验和:在计算检验和的时候,会把伪首部和UDP用户数据报连接在一起,伪首部的作用仅仅是为了计算检验和。
- 将数据看成16位的整数序列(因此如果是长度不够,需要填充0)
- 数据段的内容累加,取反,得到检验和
- 将检验和放到UDP的检验和域
- 如果接收方计算检验和,发现有误,则丢弃该UDP报文,而不做其他任何操作。
- 伪首部:
- 源 IP 地址
- 目的 IP 地址
- UDP报文的长度(这里应该指的是整个UDP的长度,即数据+UDP头部)
# 7.3 差错检测和纠错技术
奇偶校验
一比特奇偶校验:在要发送的信息D(d位)后面附加一个奇偶校验位,使得整个报文中,1的个数为奇数/偶数
可以查出任意奇数个错误,但不能发现偶数个错误。
二维奇偶校验:
- 可以检测并纠正单个比特差错。
- 能够检测(但不能纠正)分组中任意两个比特的差错。
检验和校验(运输层)
循环冗余检测(链路层)
# 7.4 TCP UDP 的区别
方面 | UDP | TCP |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
# 8. DHCP协议
# 8.1 概念
- (Dynamic Host Configuration Protocol)动态主机配置协议
- 当主机加入网络时,允许其从网络服务器动态获取其IP。
# 8.1 过程
DHCP Client以广播的方式发出DHCP Discover报文。
所有的DHCP Server都能够接收到DHCP Client发送的DHCP Discover报文,所有的DHCP Server都会给出响应,向DHCP Client发送一个DHCP Offer报文。
DHCP Offer报文中“Your(Client) IP Address”字段就是DHCP Server能够提供给DHCP Client使用的IP地址,且DHCP Server会将自己的IP地址放在“option”字段中以便DHCP Client区分不同的DHCP Server。
- DHCP Server在发出此报文后会存在一个已分配IP地址的纪录。
- DHCP Client只能处理其中的一个DHCP Offer报文,一般的原则是DHCP Client处理最先收到的DHCP Offer报文。
DHCP Client会发出一个广播的DHCP Request报文,在选项字段中会加入选中的DHCP Server的IP地址和需要的IP地址。
DHCP Server收到DHCP Request报文后,判断选项字段中的IP地址是否与自己的地址相同。
- 如果不相同,DHCP Server不做任何处理只清除相应IP地址分配记录;
- 如果相同,DHCP Server就会向DHCP Client响应一个DHCP ACK报文,并在选项字段中增加IP地址的使用租期信息。
DHCP Client接收到DHCP ACK报文后,检查DHCP Server分配的IP地址是否能够使用。
- 如果可以使用,则DHCP Client成功获得IP地址并根据IP地址使用租期自动启动续延过程;
- 如果DHCP Client发现分配的IP地址已经被使用,则DHCP Client向DHCPServer发出DHCP Decline报文,通知DHCP Server禁用这个IP地址,然后DHCP Client开始新的地址申请过程。
DHCP Client在成功获取IP地址后,随时可以通过发送DHCP Release报文释放自己的IP地址,DHCP Server收到DHCP Release报文后,会回收相应的IP地址并重新分配。
# 9.链路层协议:多路访问协议(Multiple Access Protocols)
- 目的:协调多个节点在共享广播信道上的传输。
- 冲突:两个以上的节点同时传输帧,使接收方收不到正确的帧(所有冲突的帧都受损丢失),造成广播信道时间的浪费。
# 9.1 信道划分协议
# 9.1.1 TDM(时分多路复用)
- 将时间划分为时间帧,每个时间帧再划分为N个时隙(长度保证发送一个分组),分别分配给N个节点。
- 每个节点只在固定分配的时隙中传输。
- 特点:
- 避免冲突、公平:每个节点专用速率R/N b/s。
- 节点速率有限:R/N b/s;
- 效率不高:节点必须等待它的传输时隙。
# 9.1.2 FDM(频分多路复用)
- 将总信道带宽R b/s划分为N个较小信道(频段,带宽为R/N),分别分配给N个节点。
- 特点与TDM类似:
- 避免冲突、公平:N个节点公平划分带宽;
- 节点带宽有限、效率不高:节点带宽为R/N。
# 9.1.3 码分多址(CDMA,Code Division Multiple Access)
- 给每个节点分配一个不同的代码(CDMA代码,码片序列)
- 每个节点用惟一的代码对要发送的数据进行编码
- 不同节点可以同时发送,并正确到达接收方(不会互相干扰)。
# 9.2 随机访问协议
# 9.2.1 时隙ALOHA协议
- 时间被划分为若干等长的时隙(长度为一帧的传输时间L/R s);
- 节点只在时隙的开始点传输帧;
- 所有节点同步传输,知道时隙什么时候开始;
- 如果一个时隙有多个节点同时传送,所有节点都能检测到冲突
- 当节点有新的帧要发送,需等到下一个时隙开始,才传输整个帧。 :
- 有冲突:节点检测到冲突后,以概率p在后续的每一个时隙重传该帧,直到成功。
- 无冲突:节点成功传输帧
- 特点:
- 当只有一个活动节点(有帧要发送) 时,以全速R连续传输。
- 分散的:每个节点检测冲突并独立决定何时重传;
- 没有任何访问控制,有多个活动节点时效率低,最低效率为0。
# 9.2.2 纯ALOHA协议
- 节点有帧要发,就立即传输。
- 如果与其他帧产生冲突,在该冲突帧传完之后以概率 p 立即重传该帧;
- 或等待一个帧的传输时间,再以概率 p 传输该帧,或者以概率 1-p 等待另一个帧的时间。
- 每个节点的传输与广播信道上其他节点的活动是相互独立的。
- 一个节点开始传输时并不知道是否有其他节点正在传输;
- 发生冲突时不会停止传输。
- 效率不高。
# 9.2.3 CSMA 载波侦听
- 载波侦听:某个节点在发送之前,先监听信道:
- 信道忙:有其他节点正往信道发送帧,该节点随机等待(回退)一段时间,然后再侦听信道。
- 信道空:该节点开始传输帧。
- 特点:
- 发前监听,可减少冲突。
- 由于传播时延的存在,仍有可能出现冲突,并造成信道浪费。
# 9.2.4 CSMA/CD 带冲突检测的载波侦听
- 冲突检测:如果检测到有其他节点正在传输帧,发生冲突,立即停止传输,并用某种方法来决定何时再重新传输。
- 信道忙:延迟传送
- 信道闲:传送整个帧
- 缩短无效传送时间,提高信道的利用率。
- 指数后退算法:以512比特时间为单位,第n次冲突后,等到 k < n 的随机 k * 512 比特的时间。
- 工作流程:
- 封装成帧:发送适配器从父节点获得一个网络层数据报,封装成以太网帧,放到缓冲区中;
- 适配器侦听信道:
- 空闲:即在96比特时间内(帧间最小间隔9.6μs),没有信号从信道进入,开始传输该帧;
- 忙:等待,直至侦听不到信号 (加上96 比特时间),开始传输该帧。
- 无冲突成功传输:整个帧传输期间未检测到其他适配器的信号,该帧传输成功。
- 有冲突停止传输: 传输时检测到其他适配器的信号,就停止传输帧,并传输一个48 比特的拥塞信号。
- 等待随机时间再侦听:传输拥塞信号后,适配器进入指数回退阶段,等待一段时间,并返回到第2步。
# 9.2.5 CSMA/CA 冲突避免的载波侦听
工作流程:
- 当主机需要发送一个数据帧时,首先检测信道,在持续检测到信道空闲达一个DIFS之后,主机发送数据帧。接收主机正确接收到该数据帧,等待一个SIFS后马上发出对该数据帧的确认。若源站在规定时间内没有收到确认帧ACK,就必须重传此帧,直到收到确认为止,或者经过若干次重传失败后放弃发送。
- 当一个站检测到正在信道中传送的MAC帧首部的“持续时间”字段时,就调整自己的网络分配向量NAV。NAV指出了必须经过多少时间才能完成这次传输,才能使信道转入空闲状态。因此,信道处于忙态,或者是由于物理层的载波监听检测到信道忙,或者是由于MAC层的虚拟载波监听机制指出了信道忙
CSMA/CD可以检测冲突,但无法避免冲突;对于CSMA/CA,在发送包的同时不能检测到信道上有无冲突,只能尽量避免
CSMA/CD和CSMA/CA的主要差别表现在:
- 两者的传输介质不同:CSMA/CD用于总线式以太网,而CSMA/CA用于无线局域网802.11a/b/g/n等。
- 检测方式不同:CSMA/CD通过电缆中电压的变化来检测,当数据发生碰撞时,电缆中的电压就会随着发生变化;CSMA/CA采用能量检测(ED)、载波检测(CS)和能量载波混合检测三种检测信道空闲的方式。
对于WLAN中的某个结点,其刚刚发出的信号强度要远高于来自其他结点的信号强度,也就是说它自己的信号会把其他的信号覆盖掉。
- 在WLAN中,本结点处有冲突并不意味着在接收结点处就有冲突。
# 9.3 轮流协议
# 9.3.1 轮询协议
- 指定一个主节点,以循环的方式轮询每个节点。并告诉节点能够传输的最大帧数。
- 特点:
- 消除冲突和空时隙,效率高。
- 有轮询时延:活动节点不能立即传输帧,等待被轮询;
- 如果主节点失效,整个信道都不能用。
# 9.3.2 令牌传递协议
- 设置一个令牌(token,小的专用帧);
- 令牌以固定顺序循环传递,给节点传输机会。
- 节点收到令牌后:
- 有帧要发送,传输,传完后将令牌转发到下一节点;
- 否则,直接将令牌转发到下一节点。
- 特点:
- 令牌传递是分散的,效率高。
- 一个节点的失效会使整个信道崩溃。
- 一个节点忘记释放令牌,必须恢复令牌到环中。
# 9.4 ARP协议
- Address Resolution Protocol(地址解析协议)
- 地址解析协议,负责完成逻辑地址向物理地址的动态映射,将32位逻辑地址(IP地址)转化为48位物理地址(MAC地址)
- ARP高速缓存:
- 每个主机或路由器上都有一个 ARP 高速缓存表。这个高速缓存表存放最近 Internet 地址到硬件地址之间的映射记录。
- 高速缓存表中每一项的生存时间有限,起始时间从被创建时开始算起。
- ARP协议流程:
- 当在ARP缓存中没有找到地址时,则向网络发送一个广播请求。
- 网络上的所有主机和路由器都接收和处理这个ARP请求。
- 只有是广播请求IP地址的主机或路由器 ,发回一个ARP应答分组,应答中包含它的IP地址和物理地址,并保存在请求主机的ARP缓存中。(因此存在ARP欺骗)
- 其它主机或路由器都丢弃此分组。
- 收到ARP应答后,使ARP进行请求—应答交换的IP数据报现在就可以传送了。
# 10. 路由选择算法
# 10.1 Dijkstra算法(最短通路算法)
以源节点为起点,每次找出一个到源节点的费用最低的节点,直到把所有的目的节点都找到为止。
# 10.2 距离向量选路DV算法
分布式:每个节点都从其直接相连邻居接收信息,进行计算,再将计算结果分发给邻居。
迭代:计算过程一直持续到邻居之间无更多信息交换为止。
异步:不要求所有节点相互之间步伐一致地操作。
# 10.3 层次选路算法
- 自治系统AS:
- 按区域划分的系统。每个AS由一组在相同管理者控制下的路由器组成。
- 同一个AS内的路由器可运行相同的选路算法,且拥有相互之间的信息。
- AS内部选路协议
- RIP选路信息协议
- OSPF开放最短路径优先
- AS之间选路协议:
- BGP边界网关协议
# 11. 密码学
# 11.1 混乱和扩散
- 混乱:
- 指密文和密钥之间的统计特性关系尽可能地复杂。
- 目的在于隐藏密文和密钥之间的关系,基于代替操作实现。
- 扩散:
- 重新排列消息中的数据。
- 目的在于隐藏密文和明文之间的关系,基于置换操作实现。
# 11.2 对称加密算法
# 11.2.1 DES算法(Data Encryption Standard,数据加密标准)
- 流程:
- 输入64位明文数据,并进行初始置换IP;
- 明文数据再被分为左右两部分,每部分32位,以L0,R0表示;
- 在秘钥的控制下,经过16轮迭代运算
(f)
:秘钥置换;扩展置换;S-盒代替;P-盒置换。 - 16轮后,左、右两部分交换,并连接再一起,再进行逆置换;
- 输出64位密文。
- 特点:
- 效率高,算法简单,系统开销小
- 适合加密大量数据
- 明文长度和密文长度相等
- 缺点:需要以安全方式进行秘钥交换
# 11.2.2 3DES算法
- 提出:
- 为了克服DES密钥空间小的缺陷。
- 由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解,它相当于是对每个数据块应用三次DES加密算法。
# 11.2.3 AES算法(Advanced Encryption Standard,高级加密标准)
- 流程
- 轮密钥加
- 迭代10轮:
- 逆字节变换
- 逆行移位
- 逆列混合
- 轮密钥加
- 得到明文
# 11.2.4 RC4算法(Rivest Cipher)
- 由伪随机数生成器和异或运算组成。
- RC4的密钥长度可变,范围是[1,255]。
- RC4一个字节一个字节地加解密。
- 给定一个密钥,伪随机数生成器接受密钥并产生一个S盒。
- S盒用来加密数据,而且在加密过程中S盒会变化。
# 11.2 非对称加密算法
# 11.2.1 RSA算法
- 流程:
- 随机选择两个不相等的质数p和q;
- 计算p和q的乘积n
- 计算n的欧拉函数φ(n)
- 随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。
- 计算e对于φ(n)的模反元素d。模反元素是指有一个整数d,可以使得ed被φ(n)除的余数为1。
- e和n即为公钥,d为私钥
- 加密:
c = E(m) = (m ^ e) % n
- 解密:
m = D(c) = (c ^ d) % n
- 安全性:依赖于大数分解
# 11.2.2 Elgamal算法
- 流程:
- 随机选择一个大素数 p,
- 算了,这里涉及群环域的知识,我溜了
- 安全性:取决于G上的离散对数难题
# 11.2.3 ECC算法(椭圆曲线加密算法)
# 11.3 对比
对称加密算法 | 非对称加密算法 |
---|---|
密钥管理困难(数量庞大,难分发) | 密钥管理容易 |
安全性一般 | 安全性高 |
加密速度快 | 加密速度慢 |
适合大数据量的加解密 | 适合小数据量的加解密 |
不支持签名,不能抗抵赖 | 支持数字签名 |
# 11.4 diffie-hellman密钥交换算法
- 目的:密钥交换协议/算法只能用于密钥的交换,双方可以用这个方法确定对称密钥。
- 流程:
- Alice与Bob确定两个大素数n和g,这两个数不用保密
- Alice选择另一个大随机数x,并计算A如下:A=gx mod n
- Alice将A发给Bob
- Bob 选择另一个大随机数y,并计算B如下:B=gy mod n
- Bob将B发给Alice
- 计算秘密密钥K1如下:K1=Bx mod n
- 计算秘密密钥K2如下:K2=Ay mod n
- 此时,K1=K2,因此Alice和Bob可以用其进行加解密
# 11.5 消息摘要算法
- 消息摘要算法是有关于数字签名的核心算法。
- 消息鉴别是指接收方将原始信息进行摘要,然后与接收到的摘要信息进行比对,判断接收方接收到的消息是否是发送方发送的最原始的消息。
# 11.5.1 MD5
- MD(Message Digest):消息摘要
- 流程:
- 以512位分组来处理输入的信息。
- 每一分组又被划分为16个32位子分组
- 经过了一系列的处理后,算法的输出由四个32位分组组成
- 将这四个32位分组级联后将生成一个128位散列值。
- 特点:输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);
- 作用:
- 完整性,检查是否被篡改
- 机密性,防止被看到明文
- 数字签名,防止抵赖
# 11.5.2 SHA-1
- SHA(Secure Hash Algorithm):安全散列
- 生成一个被称为消息摘要的160位(20字节)散列值。
# 11.5.3 MAC算法
- MAC(Message Authentication Code):消息认证码算法
- 除了验证消息完整性的功能,还实现了认证(确认发送者的身份)
- 消息认证码的算法中,通常会使用带密钥的散列函数(HMAC)
- 实现方式
- 利用已有的加密算法,如DES等直接对摘要值进行加密处理
- 基于MD5或者SHA-1,在计算散列值时将密钥和数据同时作为输入,并采用了二次散列迭代的方式
# 11.5.4 挑战应答机制
- 对抗重放攻击:一次性口令:
- 口令序列(x1 = f(R), x2 = f(x1), x3 = f(x2) ... xn = f(xn-1),比较xn-1` 与 xn-1)
- 挑战/应答
- 时间戳
- 思想大概一致,都是:摘要 = hash(用户名+口令 +时间/挑战值/应答)
- 客户向认证服务器发出请求,要求进行身份认证;
- 认证服务器从用户数据库中查询用户是否是合法的用户,若不是,则不做进一步处理;
- 认证服务器内部产生一个随机数,作为"质询",发送给客户;
- 客户将用户名字和随机数合并,使用单向Hash函数(例如MD5算法)生成一个字节串作为应答;
- 认证服务器将应答串与自己的计算结果比较,若二者相同,则通过一次认证;否则,认证失败;
# 11.6 数字签名
- 完整性
- 不可否认性
- 区别:
- 消息认证:
- 消息接收者证实收到的消息来自可信的源点且未被篡改的过程
- 验证消息真实性及完整性,防范第三者;
- 数字签名:收发双方产生利害冲突时,防止纠纷。
- 消息认证:
# 11.7 PKI体系(Public Key Infrastructure)
- 公钥证书:主体的身份信息、主体的公钥、CA名称,由CA签名。
- 时间戳:保证证书时效性,防止重放旧证书
- PKI 公钥基础设施:管理公开密钥和证书(生成、存储、分发、使用、验证和撤销等)的标准公开密钥管理平台。
- CA(Certificate Authority):证书机构,负责用户密钥或证书发放、更新、废止、认证等管理工作
- sub-CA:CA分级,在各地区建立Sub CA,由统一的CA给这些Sub CA签发证书,每个Sub CA维护自己的系统和用户。
- RA(Registration Authority):注册机构,负责进行各种信息审查:接收和验证用户的注册信息、证书处理请求。每个CA都有自己的RA(多个)
- CRL Issuer (Certificate revocation list,证书吊销列表):负责接收和处理RA发送来的撤销信息,定期签发CRL。
- OCSP(Online Certificate Status Protocol):一种通信协议,专门用于检查证书是否已经被撤销
# 11.8 数字证书
# 11.8.1 数字证书的申请
- 客户端准备一套公钥和私钥
- 客户端向CA机构提交公钥、以及其他个人/企业信息,认证过程可能是收费的
- CA通过线上、线下等多种渠道来验证客户端所提供的信息的真实性
- 如果信息审核通过,CA会向客户端签发认证的数字证书,证书中包含:
- 客户端最开始所提供的公钥、个人信息
- CA的信息、证书有效时间、证书序列号
- 以上都是明文的,同时还包含了CA生成的数字签名
- 这个数字签名怎么来的:
- CA 通过 Hash(客户端提供的明文信息) => 信息摘要
- CA 用自己的私钥对信息摘要进行加密 => 数字签名
# 11.8.2 数字证书的验证
- 客户端(或者浏览器)收到数字证书
- 客户端读取证书中相关的明文信息,采用CA签名时相同的Hash算法,计算得到信息摘要 A
- 利用对应的 CA 的公钥对 CA 的数字签名进行解密,得到信息摘要 B
- 比较信息摘要 A 和 B,如果两者一致,则可以确认证书是合法的。
- 更进一步地,如果这个 CA 不是根CA或者不太出名(总之就是还不够信任这个证书颁发机构 CA),需要继续查找是哪个更上一级的 CA 给这个 CA颁发的证书——层次向上认证 或者 交叉认证
# 12 IPsec
# 12.1 概念
- (IP Security,网络层安全)
- IPsec为任意两个网络层实体(主机、路由器等)之间的 IP 数据报传输提供了安全。
- IPsec是一个复杂的整体,它被定义为10多个RFC文档。
# 12.2 两种协议
- 鉴别首部协议(AH)
- 数据报格式: IP首部 + AH首部 + TCP/UDP报文段
- AH提供:鉴别、数据完整性服务,但不提供机密性服务
- 封装安全性载荷协议(ESP)
- 数据报格式:IP首部 + ESP首部 + TCP/UDP报文段 + ESP尾部 + ESP鉴别
- ESP提供:鉴别、数据完整性、机密性服务
# 12.3 传输模式与隧道模式
- 这是 IPSec VPN 进行数据封装时选择的不同的封装过程。
- 传输模式:不会改变原始报文的IP头,只会在原始IP头后面封装一些ipsec协议,比如ESP尾部。
- 隧道模式:则会在原始IP报文头前面添加新的IP头,并且在新的IP头后面封装一些ipsec协议。
# 12.4 主模式与野蛮模式
- 隧道模式,传输模式,ESP,AH说的都是IPSec VPN都已经正常建立的情况下偏向数据交换层面的事情,但是IPSec VPN还没有建立成功时,双方要进行一系列协商,这一系列的协商又要遵循什么规则呢?这个时候主模式和野蛮模式就出现了,主模式和野蛮模式主要运用在协商阶段。
- 主模式:协商6个报文,安全可靠。
- 野蛮模式:协商3个报文,不安全但效率高。
# 13. 浏览器安全
# 13.1 XSS攻击
# 13.1.1 概念:
- 全称是 Cross Site Scripting(跨站脚本),为了与“CSS”区分开来,故简称 XSS。
- 黑客往用户 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
- 当页面被注入了恶意 JavaScript 脚本时,浏览器无法区分这些脚本是被恶意注入的还是正常的页面内容,所以恶意注入 JavaScript 脚本也拥有所有的脚本权限。
- 恶意脚本可以做的事情:
- 可以窃取 Cookie 信息。恶意 JavaScript 可以通过“document.cookie”获取 Cookie 信息,然后通过 XMLHttpRequest 或者 Fetch 加上 CORS 功能将数据发送给恶意服务器;恶意服务器拿到用户的 Cookie 信息之后,就可以在其他电脑上模拟用户的登录,然后进行转账等操作。
- 可以监听用户行为。恶意 JavaScript 可以使用“addEventListener”接口来监听键盘事件,比如可以获取用户输入的信用卡等信息,将其发送到恶意服务器。黑客掌握了这些信息之后,又可以做很多违法的事情。
- 可以通过修改 DOM伪造假的登录窗口,用来欺骗用户输入用户名和密码等信息。
- 还可以在页面内生成浮窗广告,这些广告会严重地影响用户体验。
# 13.1.2 存储型XSS攻击
- 首先黑客利用站点漏洞将一段恶意 JavaScript 代码提交到网站的数据库中;
- 然后用户向网站请求包含了恶意 JavaScript 脚本的页面;
- 当用户浏览该页面的时候,恶意脚本就会被浏览器执行:具体做什么事情,看上面。
# 13.1.3 反射型XSS攻击
- 黑客通过各种方式诱导用户去点击恶意链接
- 用户将一段含有恶意代码的请求提交给 Web 服务器,Web 服务器接收到请求时,又将恶意代码反射给了浏览器端。
- 注意这里的「反射」:
- 有时候服务器需要将浏览器发送过来的数据,连带自己的一些数据也返回给浏览器
- 比如,登陆的时候输入了账号,登陆成功跳转到个人信息页面,这个页面可能就需要展示用户的账号
# 13.1.4 基于DOM的XSS攻击
- 黑客通过各种手段将恶意脚本注入用户的页面中:
- 比如通过网络劫持在页面传输过程中修改 HTML 页面的内容,这种劫持类型很多:
- 有通过 WiFi 路由器劫持的
- 有通过本地恶意软件来劫持的
- 它们的共同点是在 Web 资源传输过程或者在用户使用页面的过程中修改 Web 页面的数据
# 13.1.5 防范
- 服务器对输入脚本进行过滤、或者字符转码
- CSP策略(Content-Security-Policy,内容安全策略)
- CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。
- 一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。
- 更详细的:
- 限制加载其他域下的资源文件,这样即使黑客插入了一个 JavaScript 文件,这个 JavaScript 文件也是无法被加载的;
- 禁止向第三方域提交数据,这样用户数据也不会外泄;
- 禁止执行内联脚本和未授权的脚本;
- 还提供了上报机制,这样可以帮助我们尽快发现有哪些 XSS 攻击,以便尽快修复问题。
- HttpOnly属性:
- 由于很多 XSS 攻击都是来盗用 Cookie 的,因此还可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全。
- 使用 HttpOnly 标记的 Cookie 只能使用在 HTTP 请求过程中,所以无法通过 JavaScript 来读取这段 Cookie。
- 由于 JavaScript 无法读取设置了 HttpOnly 的 Cookie 数据,所以即使页面被注入了恶意 JavaScript 脚本,也是无法获取到设置了 HttpOnly 的数据。因此一些比较重要的数据我们建议设置 HttpOnly 标志。
# 13.2 CSRF攻击
# 13.2.1 概念
- CSRF(Cross-site request forgery)跨站请求伪造
- 黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。
- 即,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事
- 三个必要条件:
- 目标站点(的服务器端)一定要有 CSRF 漏洞;
- 用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态;
- 需要用户打开一个第三方站点,可以是黑客的站点,也可以是一些论坛。
# 13.2.2 类型
- 自动发起get请求
- 举例,在黑客的页面中,有一张图片的src对应的链接是一个转账的api,当用户被引诱进入了黑客的页面,页面被加载的时候,浏览器会自动发器img的资源请求,同时,借用用户的登录状态,就完成了这个转账的操作。
- 自动发起post请求
- 举例,在黑客的页面中,有一个隐藏的表单,表单的内容为转账的api,当用户进入这个页面,表单被自动提交,服务器就会执行转账操作。
- 引诱用户点击链接
- 举例,通过引诱用户点击某个黑客的链接,该链接为转账的api,一旦点击链接,服务器就会执行转账操作。
# 13.2.3 防范
Cookie的SameSite属性:
原理:Cookie 是浏览器和服务器之间维护登录状态的一个关键数据
实现从第三方站点发送请求时禁止 Cookie 的发送,因此在浏览器通过不同来源发送 HTTP 请求时,有如下区别:
- 如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键 Cookie 数据到服务器;
- 如果是同一个站点发起的请求,那么就需要保证 Cookie 数据正常发送。
在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项。
SameSite 选项通常有三个值:
Strict:最为严格。浏览器会完全禁止第三方 Cookie。
比如,如果你从 RANGE 的页面中访问 SIRIUS 的资源,而 SIRIUS 的某些 Cookie 设置了 SameSite = Strict 的话,那么这些 Cookie 是不会被发送到 SIRIUS 的服务器上的。
只有你从 SIRIUS 的站点去请求 SIRIUS 的资源时,才会带上这些 Cookie。
Lax:相对宽松一点。
- 在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交 Get 方式的表单这两种方式都会携带 Cookie。
- 但如果在第三方站点中使用 Post 方法,或者通过 img、iframe 等标签加载的 URL,这些场景都不会携带 Cookie。
None:在任何情况下都会发送 Cookie 数据。
验证请求的来源站点:
- 原理:由于 CSRF 攻击大多来自于第三方站点,因此服务器可以禁止来自第三方站点的请求。
- HTTP 请求头中的 Referer 和 Origin 属性
- Referer:记录了该 HTTP 请求的来源地址。
- Origin:有一些场景,不适合将来源URL暴露给服务器,因此有了这个属性,Origin属性只包含了域名信息,并没有包含具体的 URL 路径(这也是Origin和Referer的一个主要区别)
- 服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。
CSRF Token
- 在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中,然后存在 localStorage 中。
- 在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。
- 如果是从第三方站点发出的请求,那么将无法获取到 CSRF Token 的值,所以即使发出了请求,服务器也会因为 CSRF Token 不正确而拒绝请求。