前言
计算机网络这部分知识属于是非常非常重要的,科班的同学应该是在《计算机网络》专业课上已经学习过了,不过作为专业课上的知识,并没有做到和我们实际应用非常的吻合,例如对于HTTPS的讲解,大部分都是一笔带过,以及专业课上的知识大多偏向底层和专业概念的解释,并不是十分的通俗易懂(特别是对于一些量法指标的讲解,对于我这种资质愚笨的学生,属实有点强人所难)。
因此本人在完成专业课知识点的学习之后(课程 湖科大教书匠 + 书籍 计算机网络自顶向下方法),再通过学习计算机基础系列八股文的集大成者(小林coding),配合(B站 技术蛋老师)对于密码学和计算机网络知识的详细讲解,结合本人3年后端开发的学习经验,总结出本文。
接下来我将和大家,自顶向下的,学习计算机网络相关知识,碍于篇幅关系,本系列文章开通专栏(计算机网络),本篇仅介绍基础概念的理解和应用层相关知识。
概念理解
与我们常规开发使用的Controller-Service-Mapper的三层架构相似,计算机网络也有多层架构,其主要目的也是为了单一职责与解耦。
核心在于:每一层都对自己负责的功能进行封装,上层是对下层的进一步的具体功能封装。
通过上层调用下层,来实现上层功能,上层并不需要关心下层的实现。
例如:在后端开发中,我们常常需要根据不同的业务需求给出相应的接口controller,这个接口controller就需要通过调用service来实现他的具体功能,而对于service具体如何实现,以及service如何去调用mapper,controller并不需要关心。
计算机网络架构也同样如此,接下来我将和大家一起简单了解。
对于TCP/IP 网络模型,他的四层架构与架构常用的协议如下:
- 应用层 HTTP/FTP/DNS
- 传输层 TCP/UDP
- 网络层 IP
- 网络接口层
应用程序在应用层,使用应用层协议发送请求,其中,应用层类似为我们的controller,应用层协议为我们controller的具体的接口。
应用层协议基于传输层协议实现,传输层协议又基于网络层协议实现,网络层协议又基于网络接口层实现,网络接口层最后将数据交给以太网,完成交换。
这就像我们在实际开发中,前端访问接口,controller调用service,service进行数据处理后调用mapper,mapper进行数据库操作。
其中,不同的协议基于的实现也会不同,在不同的情况下,相同的协议可能采用不同的底层实现。这个也好理解,if-else判断不同的status执行不同的操作嘛。
这样以来,我们就能回答为什么计算机网络要采用分层架构了。
但是,对于每一层是干什么的,每一层是具体有哪些协议,各个协议的具体用法和之间的区别,我们还需要接着学习。
应用层
计算机网络体系架构的最顶层是应用层。
应用层只需要专注于为用户提供应用功能,比如 HTTP、FTP、Telnet、DNS、SMTP等。
对于数据如何传输、如何通信,应用层都不需要关心。
以下是官方一点的解释,大致看一眼即可(可jump
应用层直接与用户应用程序进行交互,提供用户与网络之间的接口和服务
应用协议定义:
- 数据格式化和编码:
- 应用层负责将用户数据转换为网络可传输的格式。
- 它可以对数据进行分割、封装、压缩和加密等操作,以确保数据在网络中的可靠传输和安全性。
- 用户身份验证和授权:
- 应用层提供用户身份验证和授权的机制,以保护网络资源和用户隐私。
- 这可以包括用户账号和密码验证、数字证书认证、令牌验证等方式。
- 文件传输和共享:
- 应用层提供了文件传输和共享的功能。
- 它可以通过协议如FTP来支持文件的上传、下载和管理
- 通过协议如NFS(网络文件系统)来实现分布式文件共享。
- 邮件和消息传递:
- 应用层支持电子邮件和消息传递服务。
- 它使用协议如SMTP和POP3(邮局协议版本3)来发送、接收和管理电子邮件
- 使用协议如XMPP(可扩展通讯和存在协议)来实现实时消息传递。
- 远程访问和远程控制:
- 应用层提供远程访问和远程控制的功能使用户能够远程管理和操作其他计算机或设备。
- 协议如SSH(安全外壳协议)和RDP(远程桌面协议)用于远程访问和远程控制。
HTTP协议
HTTP,全称超文本传输协议,基于传输层TCP协议实现。
HTTP定义了报文的结构以及客户和服务器进行报文交换的方式。
因为HTTP服务器并不保存关于客户的任何信息,所以我们说HTTP是一个无状态协议
HTTP支持两种连接方式
- 持续连接
- 一个TCP连接内可以发送多个HTTP请求和响应报文。
- 一般来说,如果一条连接经过一定时间间隔(一个可配置的超时间隔)仍未被使用,HTTP服务器就关闭该连接。
- HTTP的默认模式是使用带流水线的持续连接。(一个完整的HTTP请求响应完成再发下一个),不过是在一个tcp连接内完成的,还有一种是管道网络传输,这个在后面HTTP1.1的特性中会讲解。
- 非持续连接
- 每个TCP连接只传输一个请求和响应报文
在我们常规开发任务中,使用的最多的便是HTTP协议。
HTTP 报文格式
HTTP报文有两种:请求报文和响应报文。
请求报文
HTTP请求报文由:请求行、请求头、空行、请求体组成。
请求行
第一行为请求行,请求行有三个字段:方法字段、URL字段、HTTP版本字段。
- 方法字段 其中,方法字段可以取以下几种不同的值:
- GET
- POST
- HEAD
- PUT
- DELETE
注意,从规范性而言,GET应该用于获取资源、DELETE应该用于删除资源,但是,HTTP本身并没有强制的规定性,在开发者进行实现的时候,同样也可以使用GET来实现删除资源功能。
以及,大家都知道,在开发WEB应用的时候,一次POST类型的HTTP请求,会先发送一次OPTION的HTTP请求,用于校验跨域,这属于浏览器实现的规范,并不属于HTTP协议规定的内容。
所以从本质上而言,各种方法仅仅是定义了规范性的东西,只是常量名和浏览器基于常量名做了进一步规范,单独从计算机网络的角度上来说,HTTP请求报文的各个方法并没有不同。
URL字段 URL的基础概念不做解释,URL字段就是请求的完整的URL路径。
HTTP版本字段 现在主流的HTTP版本为1.0、1.1、2.0、3.0。我们最常使用的是1.1。
请求头
从第二行开始,直到遇到空行,即为连续的请求头。
请求头的格式为:头部字段名:值
HTTP自定义了一部分规范的请求头,在实际使用中,我们也可以自定义请求头。
请求体
空行之后即为请求体,请求体的格式有非常多,目前最常用的为json和formdata(传文件)。
注意,请求体任然为HTTP所定义的,在实际的浏览器操作中,会发现GET请求无法发送携带请求体,这是由于浏览器将GET请求的请求体给拦截了,并不是说GET请求就无法发请求体了,我们用postman等调试工具的时候就会发现,其实是可以携带的。
响应报文
HTTP响应报文由状态行、响应头部、空行、响应包体组成。
状态行包含了协议版本、状态码、状态描述。
响应头部、响应包体格式与请求报文的相同。
常见的状态码
常见的状态码有:
- 1XX 信息状态码
- 2XX 成功
- 3XX 重定向状态码
- 4XX 客户端错误
- 5XX 服务器错误
以下的大家看一眼即可,不需要死记硬背。。
- 1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
- 2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
- 「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。
- 「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
- 「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
- 3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
- 「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
- 「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
- 301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
- 「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
- 4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
- 「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
- 「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
- 「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
- 5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
- 「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
- 「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
- 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
- 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。
HTTP 缓存技术
HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
先做简单概述:
- 强制缓存 即为 客户端判断是否需要访问服务器 客户端在发起网络请求之前,校验本地缓存的有效时间,如果本地缓存过期,才访问服务器
- 协商缓存 即为 客户端访问服务器,服务器根据修改时间,来决定是否走缓存
并且 只有开启强制缓存 才会判断是否要走 协商缓存逻辑
强制缓存
强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的 主动性在于浏览器 这边。
强缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的,它们都用来表示资源在客户端缓存的有效期:
- Cache-Control, 是一个相对时间;
- Expires,是一个绝对时间;
如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires 。
Cache-control 选项更多一些,设置更加精细,所以建议使用 Cache-Control 来实现强缓存。具体的实现流程如下:
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。
协商缓存
当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。
协商缓存可以基于两种头部来实现。
第一种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段的意思是:
- 响应头部中的 Last-Modified:标示这个响应资源的最后修改时间;
- 请求头部中的 If-Modified-Since:
- 当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间
- 服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified)
- 如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;
- 如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:
- 响应头部中 Etag:唯一标识响应资源;
- 请求头部中的 If-None-Match:
- 当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时
- 会将请求头 If-None-Match 值设置为 Etag 的值
- 服务器收到请求后进行比对
- 如果资源没有变化返回 304
- 如果资源变化了返回 200
第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。
注意,如果Etag和If-Modified-Since都有,Etag的优先级更高。
**为什么 ETag 的优先级更高?**这是因为 ETag 主要能解决 Last-Modified 几个比较难以解决的问题:
- 在没有修改文件内容情况下文件的最后修改时间可能也会改变,这会导致客户端认为这文件被改动了,从而重新请求;
- 可能有些文件是在秒级以内修改的,If-Modified-Since 能检查到的粒度是秒级的,使用 Etag就能够保证这种需求下客户端在 1 秒内能刷新多次;
- 有些服务器不能精确获取文件的最后修改时间。
注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
HTTP版本特性与演变
HTTP 常见到版本有 HTTP/1.1,HTTP/2.0,HTTP/3.0,不同版本的 HTTP 特性是不一样的。
主要还是着重于HTTP1.1,对于2.0和3.0只做了解,以后有机会再补。
HTTP/1.1
- 无状态
- HTTP协议是无状态的,服务端无需做额外的保存状态来浪费服务端性能,但这也代表是不是每次请求都要进行身份验证呢?
- 目前主要的解决方案有:
- cookie-session
- jwt
- redis+token
- 不安全
- 明文
- 利于调试,但是信息裸奔,非常的不安全,容易被截获
- 不验证身份
- 不对通信方进行身份验证
- 如果第三方进行了拦截和伪造响应,容易受到中间人攻击等威胁
- 无法验证报文完整性
- 在请求和响应到达之前,其内容可能遭到修改
- 明文
- 支持长连接和短连接
- 短连接
- 一次tcp连接一个http请求
- 长连接
- 一次tcp连接多个http请求
- 流水线传输
- 虽然一个tcp连接包含多个http请求
- 但是必须执行完一次http请求-响应的流程,才会继续发送下一次请求
- 管道网络传输
- 可以连续发送多个http请求,并不需要等待执行完一次http请求-响应的流程
- 但是响应的顺序必须按照请求的顺序返回,因此,如果某个请求阻塞,便会造成 队头阻塞。
- 这个模式默认状态没有使用
- 短连接
HTTP/2.0
HTTP2.0的出现主要是解决HTTP1.1出现的性能问题,且HTTP2.0是基于HTTPS的,保证了安全性。
主要新出了以下四个特性:
- 头部压缩
- 二进制帧
- 并发传输
- 服务器主动推送
HTTP/3.0
HTTP/2 虽然具有多个流并发传输的能力,但是传输层是 TCP 协议,于是存在以下缺陷:
- 队头阻塞,HTTP/2 多个请求跑在一个 TCP 连接中,如果序列号较低的 TCP 段在网络传输中丢失了,即使序列号较高的 TCP 段已经被接收了,应用层也无法从内核中读取到这部分数据,从 HTTP 视角看,就是多个请求被阻塞了;
- TCP 和 TLS 握手时延,TCP 三次握手和 TLS 四次握手,共有 3-RTT 的时延;
- 连接迁移需要重新连接,移动设备从 4G 网络环境切换到 WiFi 时,由于 TCP 是基于四元组来确认一条 TCP 连接的,那么网络环境变化后,就会导致 IP 地址或端口变化,于是 TCP 只能断开连接,然后再重新建立连接,切换网络环境的成本高;
HTTP/3 就将传输层从 TCP 替换成了 UDP,并在 UDP 协议上开发了 QUIC 协议,来保证数据的可靠传输。
QUIC 协议的特点:
- 无队头阻塞,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,也不会有底层协议限制,某个流发生丢包了,只会影响该流,其他流不受影响;
- 建立连接速度快,因为 QUIC 内部包含 TLS 1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与 TLS 密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。
- 连接迁移,QUIC 协议没有用四元组的方式来“绑定”连接,而是通过「连接 ID 」来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本;
另外 HTTP/3 的 QPACK 通过两个特殊的单向流来同步双方的动态表,解决了 HTTP/2 的 HPACK 队头阻塞问题。
HTTPS协议
概念
HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
SSL是TLS的前身,现在大部分都是使用TLS1.2了。
默认端口号443
HTTP 由于是明文传输,所以安全上存在以下三个风险:
- 窃听风险,比如通信链路上可以获取通信内容。
- 篡改风险,比如强制植入垃圾广告,视觉污染。
- 冒充风险,比如冒充网站。
HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的风险:
- 信息加密:交互信息无法被窃取
- 校验机制:无法篡改通信内容,篡改了就不能正常显示
- 身份证书:证明网站真实性
HTTPS 是如何解决上面的三个风险的?
- 混合加密的方式实现信息的机密性,解决了窃听的风险。
- 摘要算法的方式来实现完整性,它能够为数据生成独一无二的「指纹」,指纹用于校验数据的完整性,解决了篡改的风险。
- 将服务器公钥放入到数字证书中,解决了冒充的风险。
接下来简单介绍 混合加密、摘要算法、数字证书 三者的概念
混合加密
通过混合加密的方式可以保证信息的机密性,解决了窃听的风险。
HTTPS 采用的是 对称加密和非对称加密结合 的「混合加密」方式:
- 对称加密
- 使用相同的私钥进行加密和解密
- 速度快。
- 非对称加密
- 服务器掌管 私钥和公钥 私钥不分发,公钥可分发,客户端使用公钥加密,服务端使用私钥解密,也可以服务端使用公钥加密,客户端使用私钥解密。
- 速度慢
- 并且,公钥加密的数据用公钥是解密不了的,私钥同理
HTTPS是这样使用的混合加密:
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
摘要算法 + 数字签名
用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的「指纹」,这个哈希值是唯一的,且无法通过哈希值推导出内容。
通过哈希算法可以确保内容不会被篡改,但是并不能保证「内容 + 哈希值」不会被中间人替换,因为这里缺少对客户端收到的消息是否来源于服务端的证明。
通过非对称加密算法来解决。
- 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
- 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
一般我们不会用非对称加密来加密实际的传输内容,因为非对称加密的计算比较耗费性能的。
所以非对称加密的用途主要在于通过「私钥加密,公钥解密」的方式,来确认消息的身份,我们常说的数字签名算法,就是用的是这种方式,不过私钥加密内容不是内容本身,而是对内容的哈希值加密。
私钥是由服务端保管,然后服务端会向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,就说明该消息是由服务器发送的。
数字证书
可以通过哈希算法来保证消息的完整性; 可以通过数字签名来保证消息的来源可靠性(能确认消息是由持有私钥的一方发送的);
通过数字证书来保证数字签名是可信的,ca机构。
建立连接的流程
SSL/TLS 协议基本流程:
- 客户端向服务器索要并验证服务器的公钥。
- 双方协商生产「会话秘钥」。
- 双方采用「会话秘钥」进行加密通信。
前两步也就是 SSL/TLS 的建立过程,也就是 TLS 握手阶段。
TLS 的「握手阶段」涉及四次通信,使用不同的密钥交换算法,TLS 握手流程也会不一样的,现在常用的密钥交换算法有两种:RSA 算法和 ECDHE 算法。
基于RSA算法
传统的 TLS 握手基本都是使用 RSA 算法来实现密钥交换的。
RSA算法概述
RSA算法是一种经典的非对称加密算法,它的数学原理是 大数分解的困难性。(数学原理大家有兴趣自己看吧)。
通过RSA算法我们可以生成一对公钥和私钥,用于加密通信、数字签名等等。
一、第一次握手
- 建立tcp连接
- 客户端向服务器发起加密通信请求,也就是 ClientHello 请求(第一次握手)
- 携带 TLS 协议版本
- 客户端生成随机数 客户端随机数
- 客户端支持的密码套件列表 如RSA加密算法等等,来让服务端选一个进行交互
- 服务器返回ack表示接收成功
二、第二次握手
- 服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello(第二次握手)
- 确认TLS协议版本 如果浏览器不支持 关闭加密通信
- 服务器生成随机数 用于生成 会话密匙 服务端随机数
- 确认的密码套件列表
- 服务端发送 Server Certificate
- 服务器的数字证书
- 服务端发送server hello done表示发送完毕
- 客户端发送ack表示接收成功
- 客户端收到服务器的回应后
- 通过浏览器或者操作系统中的CA公钥,确认服务器数字证书真实性
- 从数字证书取出服务器公钥
客户端拿到了服务端的数字证书后,要怎么校验该数字证书是真实有效的呢?
数字证书
数字证书通常包含了:
- 公钥;
- 持有者信息;
- 证书认证机构(CA)的信息;
- CA 对这份文件的数字签名及使用的算法;
- 证书有效期;
- 还有一些其他额外信息;
那数字证书的作用,是用来认证公钥持有者的身份,以防止第三方进行冒充。
数字证书签发和验证流程
CA 签发证书的过程:
- 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
- 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程:
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
所以,只要客户端的主机没有去信任一些伪造的证书,那么https就是安全的。
三、第三次握手
- 客户端发送 client key exchange
- 生成一个新的随机数 pre-master随机数
- 用 提取的服务器公钥 加密随机数
- 服务端收到后
- 使用服务端私钥 解密
- 提取出随机数
- 客户端和服务端 根据三个随机数 生成 会话密钥
- 三个随机数为
- 第一次握手时 客户端生成的随机数
- 第二次握手时 服务端生成的随机数
- 第三次握手时 客户端又一次生成的随机数,这个随机数通过公钥加密,服务端私钥解密,所以这个随机数是无法被中间人所获取的。
- 客户端发送 change cipher spec
- 告诉服务端开始使用 会话密匙 通过对称加密方式 发送消息
- 客户端发送 Finished
- 把之前所有发送的数据做个摘要
- 再用 会话密钥 加密一下
- 让服务器做个验证
- 验证加密通信「是否可用」和「之前握手信息是否有被中途篡改过」。
- 服务端 返回 ack
四、第四次握手
- 服务端也进行 change cipher spec 和 finished 客户端返回ack
- 之后就是正常的http请求了 只是使用 会话密钥 加密
基于ECDHE算法
ECDHE 密钥协商算法是 DH 算法演进过来的,所以我们先从 DH 算法说起。
DH算法
DH 算法是非对称加密算法,它可以用于密钥交换,核心思想是生成一个通信双方共享的私钥
该算法的核心数学思想是 离散对数。
离散对数的公式:
a的i次方 mod p = b
i 称为 b 以 a 为底的 mod p的 离散对数。
底数 a 和模数 p 是离散对数的公共参数,也就说是公开的,b 是真数,i 是对数
知道了对数,就可以用上面的公式计算出真数(b)。但反过来,知道真数却很难推算出对数(i)。
特别是当模数 p 是一个很大的质数,即使知道底数 a 和真数 b ,在现有的计算机的计算水平是几乎无法算出离散对数(i)的,这就是 DH 算法的数学基础。
因此,根据此数学问题,定义如下:
通信的双方,首先公共约定P和G作为mod和底数。(P G 暴露)
然后,通信的双方定义自身私钥a和b。
通信的双方定义公钥A和B。公钥的生成为 G的a或b次方 mod P (A和B 暴露)
通信双方交换公钥,继续代入公式 即 A或B的b或a次方 mod P 得到的结果是相同的,这便是后续用于加密的密匙。
DHE算法
根据私钥生成的方式,DH 算法分为两种实现:
- static DH 算法,这个是已经被废弃了;
- DHE 算法,现在常用的;
static DH 算法里有一方的私钥是静态的,也就说每次密钥协商的时候有一方的私钥都是一样的,一般是服务器方固定,即 a 不变,客户端的私钥则是随机生成的。
于是,DH 交换密钥时就只有客户端的公钥是变化,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,因为密钥协商的过程有些数据是公开的,黑客就可以依据这些数据暴力破解出服务器的私钥,然后就可以计算出会话密钥了,于是之前截获的加密数据会被破解,所以 static DH 算法不具备前向安全性。
既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通信时,都是随机生成的、临时的,这个方式也就是 DHE 算法,E 全称是 ephemeral(临时性的)。
所以,即使有个牛逼的黑客破解了某一次通信过程的私钥,其他通信过程的私钥仍然是安全的,因为每个通信过程的私钥都是没有任何关系的,都是独立的,这样就保证了「前向安全」。
ECDHE算法
DHE 算法由于计算性能不佳,因为需要做大量的乘法,为了提升 DHE 算法的性能,所以就出现了现在广泛用于密钥交换算法 —— ECDHE 算法。
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
在之前介绍DH算法的时候介绍过,DH算法的核心就是对于 离散对数 的使用,而离散对数的性能还是较差,因为要进行多次幂运算,因此 ECDHE算法 使用 ECC椭圆曲线特性 来优化性能
反正核心都是一样的,定义公开的信息,然后双方持有私有的信息,通过公开的信息与私有的信息加密,最后形成双方的加密密钥。
关于ECC椭圆曲线特性的内容,本来想挖坑的,但是挖坑后面的ECDHE握手过程就讲不明白了,想了一下还是来补上了。
ECC椭圆曲线
对于椭圆曲线,非数学专业应该也不知道他长什么样,没关系我也不知道。。。 我们只需要知道,对于椭圆曲线,有这么一个类似于定义的概念,给定两个点A和B,那么可以算出一个点C的位置,C的位置为A.B的结果。 也就是说,通过给定的两点,通过点运算,是可以得到确定的第三点的。 而且,A和B不一定要是两个不同的点,因此也可以是A.A=C,并且在定义上可以认定为,C=2A。 那么同样可以算出D=4A,E=6A等等这样的点。 但是E=6A就很暧昧了,他可以是2A.3A,也可以是2A.2A.2A来的。 想象一下,在以下伪代码情况下:
int G = 1;//定义点G
int privatekey = 100;//我自己的私人定制
Integer result;
for(int i =0 ;i<100;i++){
if(result == null){
result = G.privateKey;
}else{
result = result.privateKey;
}
}
这样执行完成后,我们就得到了确认的result点,但是要逆向知道这个result是经过什么过程来的,那几乎是无法做到的事情(因为执行多少次也是随机的)。 这样我们可以用来做什么事情呢? 我们定义通信的双方客户端-服务端。 客户端和服务端统一声明G点。 客户端生成 私钥1 然后通过私钥1和G点,生成result1。 服务端生成 私钥2 然后通过私钥2和G点,生成result2。 然后客户端和服务端交换result1和result2。 客户端根据 私钥1 result2 再进行生成操作 生成 加密密钥。 服务端根据 私钥2 result1 再进行生成操作 生成 加密密钥。 这个 加密密钥 一定是相同的。 为什么一定是相同的呢? 其实核心原理就是 G.私钥1*n.私钥2*n = G.私钥2*n.私钥1*n
这样是不是清晰多了。。 那有些,观察力好的同学就能发现,那这个ECC,不还是有幂次计算吗,但是相较于DH算法的幂次,这个点运算要快很多。。所以是这样的个优化流程
ECDHE握手过程
ECDHE可以解决RSA算法的向前安全性问题。
接下来,分析每一个 ECDHE 握手过程。
第一次握手
和RSA一样。
- 建立tcp连接
- 客户端向服务器发起加密通信请求,也就是 ClientHello 请求(第一次握手)
- 携带 TLS 协议版本
- 客户端生成随机数 客户端随机数(这个随机数仅是用于扩大复杂度的)
- 客户端支持的密码套件列表
- 服务器返回ack表示接收成功
第二次握手
这里开始就和RSA不一样了。
- 服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello(第二次握手)
- 确认TLS协议版本 如果浏览器不支持 关闭加密通信
- 服务器生成随机数 用于生成 会话密匙 服务端随机数
- 确认的密码套件列表
- 服务端发送 Server Certificate
- 服务器的数字证书
- 服务端 生成随机数作为 服务端私钥 保存本地
- 服务端发送 Server Key Exchange
- 选择的椭圆曲线 这样 基点G 就定好了
- 根据 G和私钥 计算ECC公钥 (这就是服务端的result1)
- 注意 这个ECC公钥,必须是被服务器的数字证书所加密过的,由此来抵制中间人修改ECC公钥,造成的攻击。
- 服务端发送server hello done表示发送完毕
- 客户端发送ack表示接收成功
- 客户端收到服务器的回应后
- 通过浏览器或者操作系统中的CA公钥,确认服务器数字证书真实性
- 从数字证书取出 服务器公钥
第三次握手
- 客户端 生成随机数作为 客户端椭圆曲线的 私钥
- 客户端 根据私钥+G 生成 客户端的椭圆曲线 公钥
- 客户端 Client Key Exchange
- 发送客户端公钥
- 客户端公钥不需要进行加密了
- 客户端 服务端 根据对方公钥 自己私钥 基点 计算出 共享密钥
- 使用 客户端随机数+服务端随机数+共享密钥 生成最终 会话密钥
- 算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信。
- 接着,客户端会发「Encrypted Handshake Message」消息,把之前发送的数据做一个摘要,再用对称密钥加密一下,让服务端做个验证,验证下本次生成的对称密钥是否可以正常使用。
第四次握手
最后,服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。于是,就可以正常收发加密的 HTTP 请求和响应了。
总结
总结一下两个算法的区别
- RSA算法,主要是通过给客户端 数字证书,客户端保证数字证书正确的情况下,解析获取到正确的 服务端公钥 ,用公钥来加密随机数 发送给服务端,服务端用私钥解密随机数,这样就不会被破解获取了。
- ECDHE算法,也是通过数字证书,将服务端给的result1进行解密获取,防止被中间人修改,这样才能进行正常的交互。
RPC协议
RPC(Remote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式。
用于调用一些远程方法,什么叫远程方法?比如微服务系统中,微服务A调用微服务B的接口,如果使用HTTP框架进行调用,那就写的很繁琐很麻烦,使用RPC框架的架构去调用,就像调用本地方法一样,非常的方便。
注意,TCP出身于70年代,RPC出身于80年代,HTTP出身于90年代。
现在电脑上装的各种联网软件,比如 xx管家,xx卫士,它们都作为客户端(Client)需要跟服务端(Server)建立连接收发消息,此时都会用到应用层协议,在这种 Client/Server (C/S) 架构下,它们可以使用自家造的 RPC 协议,因为它只管连自己公司的服务器就 ok 了。
但有个软件不同,浏览器(Browser),不管是 Chrome 还是 IE,它们不仅要能访问自家公司的服务器(Server),还需要访问其他公司的网站服务器,因此它们需要有个统一的标准,不然大家没法交流。于是,HTTP 就是那个时代用于统一 Browser/Server (B/S) 的协议。
因此现在RPC协议主要是用于微服务之间的消息通讯,而且各大框架对于RPC协议的实现也各不相同。
WebSocket协议
我们知道 TCP 连接的两端,同一时间里,双方都可以主动向对方发送数据。这就是所谓的全双工。
而现在使用最广泛的HTTP/1.1,也是基于TCP协议的,同一时间里,客户端和服务器只能有一方主动发数据,这就是所谓的半双工。
为了解决HTTP半双工的问题,因此推出了新的应用层协议WebSocket,它支持全双工通信。
建立连接的流程
在TCP三次握手结束之后,浏览器会发送一次HTTP请求。
- 如果此时是普通的 HTTP 请求,那后续双方就还是老样子继续用普通 HTTP 协议进行交互,这点没啥疑问。
- 如果这时候是想建立 WebSocket 连接,就会在 HTTP 请求里带上一些特殊的header 头
携带的特殊header头如下:
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
这些 header 头的意思是,浏览器想升级协议(Connection: Upgrade),并且想升级成 WebSocket 协议(Upgrade: WebSocket)。同时带上一段随机生成的 base64 码(Sec-WebSocket-Key),发给服务器。
如果服务器正好支持升级成 WebSocket 协议。就会走 WebSocket 握手流程,同时根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,放在 HTTP 响应的 Sec-WebSocket-Accept 头里,同时带上101状态码,发回给浏览器。
HTTP 的响应如下:
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n
之后,浏览器也用同样的公开算法将base64码转成另一段字符串,如果这段字符串跟服务器传回来的字符串一致,那验证通过。
这样WebSocket连接就建立完成了。
WebSocket的消息格式
数据包在WebSocket中被叫做帧
WebSocket的消息格式也是 消息头+消息体组成
消息头:
- FIN: 表示这是一条完整的消息,一般情况下都是1。
- RSV1、RSV2、RSV3: 暂时没有使用,一般都是0。
- Opcode: 表示消息的类型,包括文本消息、二进制消息等。
- 等于 1 ,是指text类型(string)的数据包
- 等于 2 ,是二进制数据类型(
[]byte
)的数据包 - 等于 8 ,是关闭连接的信号
- Mask: 表示消息是否加密。
- Payload length: 表示消息体的长,单位是字节。
- 长度分了多个块去存,分别是:7、16、32、16位
- 无论如何,先读取前7位,根据前七位的值来判断
- 0-125 只读这7位就可以了
- 126 还要再读16位
- 127 还要再读64位
- Masking key: 仅在消息需要加密时出现,用于对消息进行解密。
消息体单位是字节。
DHCP协议
动态主机配置协议(Dynamic Host Configuration Protocol,简称DHCP)是一种网络协议,用于自动分配IP地址和其他网络配置参数给网络中的设备。
以下是DHCP协议的基本工作过程:
- DHCP发现:
- 当设备加入网络时,它会广播一个DHCP发现消息,寻找可用的DHCP服务器。
- DHCP提供:
- DHCP服务器接收到DHCP发现消息后,会广播一个DHCP提供消息,其中包含IP地址和其他网络配置参数。多个DHCP服务器存在时,设备可能会收到多个提供消息。
- DHCP请求:
- 设备选择其中一个DHCP服务器提供的IP地址和配置参数,并向该服务器发送一个DHCP请求消息,请求使用提供的配置。
- DHCP确认:
- DHCP服务器收到DHCP请求消息后,会确认设备的请求,并回复一个DHCP确认消息,其中包含设备所请求的IP地址和其他配置参数。
- IP地址租约:
- DHCP协议使用IP地址租约的概念。IP地址租约是指DHCP服务器为设备提供的IP地址和配置参数的使用期限。设备在租约到期前需要更新租约,否则会失去IP地址。
- 配置更新:
- 在租约到期前,设备可以向DHCP服务器发送配置更新请求,以延长租约的有效期或请求新的配置参数。
DHCP协议的优点包括:
- 自动化配置:DHCP协议自动为设备分配IP地址和配置参数,无需手动配置,简化了网络管理和维护的工作。
- 灵活性:DHCP协议支持动态分配IP地址,可以根据网络中设备的数量和需求进行灵活管理。
- 集中管理:通过DHCP服务器,可以集中管理网络中的IP地址分配和配置信息,简化了网络管理工作。
DHCP协议在大多数局域网中被广泛应用,使得设备可以方便地连接到网络并获取必要的网络配置。
DHCP客户使用的UDP端口号为68,服务器使用UDP端口号为67
DNS
DNS(Domain Name System,域名系统)是计算机网络中的应用层协议,用于将域名(例如www.example.com)转换为对应的IP地址(例如192.0.2.1),以实现互联网上的主机之间的通信。
层次结构
域名系统采用层次化的树状结构,以域名的顶级域(例如.com、.net)开始,然后依次向下划分为二级域、三级域,以此类推。 最低级的域名单元是主机名,例如www.example.com中的www。
DNS查询过程
当用户在浏览器中输入一个域名时,操作系统会首先检查本地的DNS缓存,如果找到了对应的IP地址,则直接返回结果,否则进行下一步查询。
- 如果本地缓存中没有找到对应的IP地址,操作系统会向本地DNS服务器发起递归查询请求。
- 本地DNS服务器一般由互联网服务提供商(ISP)或企业内部配置,它会首先查询自己的缓存,如果找到了对应的IP地址,则返回结果给操作系统,否则进行下一步查询。
- 如果本地DNS服务器也没有找到对应的IP地址,它会向根DNS服务器发起请求,具体分为两种情况。
- 两种查询情况
- 递归查询
- 递归查询是一种查询方式,其中DNS服务器在查询过程中负责向其他DNS服务器发送查询请求,并在收到结果后直接返回给客户端。
- 当本地DNS服务器向根DNS服务器发起递归查询时,根DNS服务器会根据自己的缓存或其他配置向下级DNS服务器查询,并将结果返回给本地DNS服务器。
- 本地DNS服务器继续向下级DNS服务器发起递归查询,直到找到负责解析目标域名的DNS服务器,并将结果返回给客户端。
- 递归查询方式相比迭代查询方式减少了查询的次数,提高了查询效率。
- 迭代查询
- 迭代查询是一种查询方式,其中DNS服务器在查询过程中负责向其他DNS服务器发送查询请求,并将结果逐级返回给客户端。
- 根DNS服务器是域名系统的顶级服务器,它存储了顶级域的DNS服务器信息。本地DNS服务器会向根DNS服务器查询顶级域的DNS服务器地址。
- 根DNS服务器返回顶级域的DNS服务器地址给本地DNS服务器,然后本地DNS服务器继续向顶级域的DNS服务器查询下一级域的DNS服务器地址。
- 这个过程会一直迭代下去,直到找到负责解析目标域名的DNS服务器。
- 递归查询
使用UDP协议封装,运输层端口号为53。
FTP
FTP(File Transfer Protocol,文件传输协议)是一种用于在计算机网络中传输文件的标准协议。它提供了一种简单的方式,使用户能够上传和下载文件到远程服务器或从远程服务器获取文件。
FTP协议涉及两个主要角色:客户端和服务器。
- 客户端是发起文件传输请求的计算机,通常是用户所在的计算机。
- 服务器是存储文件并提供文件传输服务的计算机。
FTP使用两个连接来完成文件传输:控制连接和数据连接。
- 控制连接用于发送控制命令和传输命令参数,如登录、列出文件、改变目录等。 21端口
- 数据连接用于实际的文件传输,包括上传和下载文件。
FTP提供了两种工作模式:主动模式和被动模式。
- 在主动模式下,客户端在数据连接建立前会主动向服务器发起连接请求。 20端口
- 在被动模式下,服务器被动等待FTP客户的连接。
FTP协议支持多种用户身份验证方式,例如基于用户名和密码的验证,以及匿名访问。
- 在基于用户名和密码的验证中,客户端需要提供有效的用户名和密码才能登录到服务器。
- 匿名访问允许用户以匿名身份登录到服务器,通常使用预定义的用户名(如"anonymous")和空密码。
原始的FTP协议是明文传输的,因此在传输过程中可能存在安全风险。 为了增加安全性,可以使用安全的FTP协议(FTPS)或通过VPN等其他安全通道来保护FTP传输。
邮件协议
分为传统和新型两类:
- 传统
- 使用SMTP传送
- 用户代理使用SMTP传送到邮件服务器
- 邮件服务器之间使用SMTP进行发送
- 使用POP3接收
- 接收方使用POP3从邮件服务器获取
- 使用SMTP传送
- 新型
- 用户与邮件服务器之间采用HTTP协议
- 邮件服务器之间使用SMTP协议
SMTP
基于TCP 端口号25; 只传送ASCII文本。 如果要传送非ASCII文本,需要使用MIME进行包装。
SMTP(Simple Mail Transfer Protocol)是一种用于电子邮件传输的标准协议。下面是SMTP协议的基本流程:
- TCP连接建立:客户端(邮件发送方)通过TCP与邮件服务器(邮件接收方的SMTP服务器)建立连接,默认端口号是25。
- 握手阶段:建立TCP连接后,客户端和服务器之间进行握手。客户端发送一个“HELO”或“EHLO”命令给服务器,服务器响应并确认连接。
- 发送邮件:客户端发送一个“MAIL FROM”命令,指定邮件的发件人。然后发送一个或多个“RCPT TO”命令,指定邮件的收件人。每个“RCPT TO”命令只能指定一个收件人。
- 邮件数据:客户端发送一个“DATA”命令,表示接下来要发送邮件的内容。客户端发送邮件头部信息,包括发件人、收件人、主题等。然后发送邮件正文内容。
- 结束数据:当邮件正文发送完毕后,客户端发送一个“.”命令表示邮件数据结束。
- 服务器响应:服务器接收到邮件数据后,返回一个响应码,表示邮件是否接收成功。
- 断开连接:客户端发送一个“QUIT”命令给服务器,表示结束邮件传输。服务器确认断开连接,并关闭与客户端的TCP连接。
以上是SMTP协议的基本流程。需要注意的是,实际的SMTP流程可能还包括身份验证、加密等步骤,以确保邮件传输的安全性和可靠性。另外,SMTP协议只负责邮件的传输,不涉及邮件的读取和存储,这些功能由其他协议(如POP3、IMAP)来实现。
POP3
邮件读取协议 用户只可以下载删除或下载保留 不能管理邮件服务器上的邮件 TCP 段偶110
IMAP
邮件读取协议 用户可操作邮件服务器上的邮件 TCP 端口143
总结
本文主要讲了网络分层概念和应用层协议,着重讲了HTTP和HTTPS,下一篇文章会讲解传输层协议TCP和UDP。
参考
小林coding
蛋老师