OSI七层模型
OSI模型各层的基本作用:
ARP协议
每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。
如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。
TCP/UDP
UDP(用户数据报协议)
UDP是传输层的协议,功能即为在IP的数据报服务之上增加了最基本的服务:复用和分用以及差错检测。
-
结构
- 源端口号和对端口号:表示了哪两个主机进行通信;
- 数据报长度:完整UDP报文长度;
- 校验和:检验收发数据是否一致;
- 源端口号和对端口号:表示了哪两个主机进行通信;
-
特点
-
无连接
-
尽最大努力交付
-
面向报文
- 即不合并、也不拆分
-
-
功能
-
复用
-
分用
-
差错检测
-
TCP(传输控制协议)
TCP将用户数据打包构成报文段,它发送数据时启动一个定时器,另一端收到数据进行确认,对失序的数据重新排序,丢弃重复的数据。TCP提供一种面向连接的可靠的字节流服务,面向连接意味着两个使用TCP的应用(B/S)在彼此交换数据之前,必须先建立一个TCP连接,类似于打电话过程,先拨号振铃,等待对方说喂,然后应答。
-
结构
- 序号和确认序号进行包管理,对数据进行排序
- 头长:标识tcp头部大小;
- 标志位:ACK、SYN、FIN
- 窗口大小:TCP流量控制窗口大小
- 紧急指针:发送紧急数据时会用到
- 选项数据:一个可选的信息
- 序号和确认序号进行包管理,对数据进行排序
-
特点
- 面向连接
-
可靠传输
-
停止等待协议
- 无差错情况(无差错)
-
超时重传(不丢失)
- 确认丢失(不重复)
-
确认迟到(按序到达)
-
-
面向字节流
-
流量控制
-
滑动窗口协议
- 接收方有接收缓存,如果发送速度过快,可能造成
溢出。
- 接收方有接收缓存,如果发送速度过快,可能造成
-
接收方可以动态调整发送方的
发送窗口,达到动态调整发送速率的目的。发送窗口和接收窗口是两个字段,位于TCP报文的首部。
-
拥塞控制
- 慢开始、拥塞避免
-
快恢复、快重传
-
面向连接
TCP是面向连接的协议,建立和断开连接需要经过7步,三次握手建立连接,四次挥手断开连接。
TCP连接的三次握手
- 客户端-发送SYN数据包,服务端确认了自己接受正常,对方发送正常;
- 服务端-发送SYN/ACK数据包,客户端确认了双方发送接收正常;
- 客户端-发送ACK数据包,服务端确认了自己发送,对方接收正常;
TCP断开连接的四次挥手
-
断开连接时,需要分别断开
客户端到服务器,服务器到客户端的链接。 -
客户端发送6.FIN,服务器接收后返回7.ACK,即断开客户端到服务器的链接。这一阶段服务端依旧可以向客户端发送消息
-
此时处于
半关闭状态,如果服务器还有未发送完的信息,可以继续从服务器向客户端发送信息。 -
服务器向客户端发送8.FIN,ACK,客户端发送9.ACK,即断开服务器到客户端的链接。
Q:为什么要进行三次握手而不是两次?
-
是为了解决超时场景。
-
如果第一个
1.SYN超时,客户端会重新发送一次1.SYN。 -
服务器在收到第二次SYN后,会发送确认信息,建立连接。 -
如果没有第三次握手,那么第一个超时
1.SYN可能会再次发送给服务器,服务器会认为客户端想再次建立一个新的链接。 -
如果有第三次握手,那么第一个超时
1.SYN会接收到服务器的2.SYN,但是不会再发送1.ACK给服务器,就不会再建立一个新的链接。
Q:为什么是四次挥手而不是三次?
为了保证通信双方都能通知对方 需释放 & 断开连接。 关闭连接时,服务端收到客户端的FIN报文时,仅仅表示客户端不再发送数据了但是还能接收数据,服务端也未必全部数据都发送给对方了,所以服务端可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,服务端ACK和FIN一般都会分开发送。
可靠传输
通过序列号和确认应答提高可靠性。
当客户端发送数据之后需等待对端的确认信息。如果收到确认应答,表示数据成功发送到对端。如果在一定时间内没有收到确认应答,则认为数据已丢失,需要重新发送。未收到应答消息,两种情况数据丢失,另一种是应答消息丢失。应答信号丢失,重新发送对端就会重复接收相同的数据,为了解决目标端重复接收相同数据,可以通过为发送数据的每个字节标上序号,接收端收到数据根据首部序号和长度,将下一次应该的接收的序号作为应答返回出去。这样就可以通过序列号和确认应答,实现可靠传输。
重发超时如何确定
上面提到客户端在超过一定时间没有接收到应答消息会进行数据重发。那么这个超时时长是多少呢?理想状态下,找到一个小的时间,确保应答消息在该时间段中可以返回,但是不同的网络环境下这个时间会发生变化。TCP为了在不同网络环境下都能提供高性能通信,为此每次发送数据都会计算往返时间及其偏差。超时时间比这个往返时间与偏差的和稍大一点的时间。
面向字节流
TCP在建立连接时,会确认一次数据包传输的单位。称之为“最大消息长度(MSS)”。建立连接客户端SYN消息中携带一个MSS值,服务器的返回的SYN中也会携带一个MSS值,最终会选择两者中较小的按个作为数据包的传输单位。
滑动窗口流量控制
TCP以一个MSS大小传输数据,往返时间越长,网络的吞吐量也差。为了解决这个问题,引入了窗口的概念。发送端在发送一个段后不需要等待应答信息进行发送数据。窗口大小是指无需等待应答消息继续发送数据的最大值。窗口提供了缓存机制,实现对多个段同时应答的功能。
拥塞控制
为了解决大量数据对网络的影响,通过慢启动算法得出的值,对发送数据量进行控制。
TCP滑动窗口
窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。
发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。
接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
TCP流量控制
流量控制是为了控制发送方发送速率,保证接收方来得及接收。接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
TCP拥塞控制
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
发送方需要维护一个叫做**拥塞窗口(cwnd)**的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。
为了便于讨论,做如下假设:
- 接收方有足够大的接收缓存,因此不会发生流量控制;
- 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
-
慢开始与拥塞避免
发送的最初执行慢开始,令
cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 指数增大,因此之后发送方能够发送的报文段数量为:2、4、8 ...注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,这里初始
ssthresh = 24,当cwnd >= ssthresh时,进入拥塞避免,每个轮次只将 cwnd 加 1,即 cwnd 加法增大(如①、③)。如果出现了超时(如②),则令
cwnd = 1,ssthresh = cwnd / 2 = 12,然后重新执行慢开始。 -
快重传与快恢复
在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2(如④),则 M3 丢失,立即重传 M3。
在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令
ssthresh = cwnd / 2 ,cwnd = ssthresh = 8(如⑤)。慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
TCP的粘包
- tcp粘包指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
- 解决方案 1、发送方 对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。 2、接收方 接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。 3、应用层 应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。 解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢? 格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开始符和结束符时一定要确保每条数据的内部不包含开始符和结束符。 发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。
- UDP会粘包吗? 不会。 TCP为了保证可靠传输并减少额外的开销(每次发包都要验证),采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的(保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息)。 UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。
Q:请简单说一下TCP/UDP的区别?
- TCP面向连接,UDP面向非连接即发送数据前不需要建立连接。
- TCP提供可靠的服务,UDP无法保证。
- TCP面向字节流,UDP面向报文。
- TCP数据传输慢,UDP数据传输快。
- TCP传输不限制大小,UDP单次传输报文有限制(64K)。
Q:TIME_WAIT的时间为什么是2msl?,为什么要超时等待?
msl:Maximum Segment Life,表示TCP 对TCP Segment 生存时间的限制。可以理解为,数据包在网络上存活的最长时间,一来一回的话,就是2倍。 为什么需要超时等待? 如果服务端没有收到第四次挥手的内容,那么服务端会再次发过来,那么,客户端就需要等着,看服务端会不会再次发送数据过来,如果超过这2sml时间服务端还没有发数据过来,那客户端就认为服务端已经接收到第四次挥手发送的数据了,然后连接正式关闭。 在进行第四次挥手的时候,客户端会将ACK报文发送给服务端,由于tcp是建立在面向连接的基础上的–“有来有往”,正常情况下,服务端需要返回给客户端一个ACK数据包,告诉客户端,我已经收到你的ACK包了,但是,这样会需要一直一来一回;然而,咱们的四次挥手里面就有这样的机制,就是在被动关闭的一端(本文案例中指的是服务端),服务端在第四次挥手的时候,需要有一个超时时间等待,比如说4s,如果超出4s的超时时间,服务端没有接收到客户端发来的第四次挥手的数据,那么服务端会把第三次挥手的内容再次发送(服务端以为客户端没有收到它发的第三次挥手的内容,所以又发了一次,但是实际上客户端收到并且发送了第四次挥手的数据包),此时,我们的TIME_WAIT就发挥作用了,它是主动发起断开连接的一方的需要进行的等待实际时间,等待的作用就是,如果服务端没有收到第四次挥手的内容,那么服务端会再次发过来,那么,客户端就需要等着,看服务端会不会再次发送数据过来,如果超过这2sml时间服务端还没有发数据过来,那客户端就认为服务端已经接收到第四次挥手发送的数据了。
Q:TCP发数据过程中必须按顺序接收吗?
在TCP协议当中,每个包都有一个短期不重复的序列号。数据达到主机不一定按照顺序,但是TCP协议栈会自动排序再交到应用层。
Q:TCP如何保证传输的可靠性?
校验和、流量控制、拥塞控制、ARQ协议、超时充传机制
-
校验和:校验和有误,则丢弃当前报文段;
-
流量控制:接收方有一个固定的缓冲区,发送方只允许发送缓冲区能接纳的数据,如果接收方来不及处理,则通知发送方降低发送速率,防止包丢失。TCP使用滑动窗口来进行流量控制,确认方通过报文中的窗口字段,影响发送方速率。
-
拥塞控制:当网络拥塞时减少数据发送。TCP维护拥塞窗口cwnd变量(还有拥塞门限ssthresh),并进行动态变化。有慢开始、拥塞避免、快重传、快恢复四种算法。
- 慢开始:cwnd < ssthresh, cwnd每次翻倍;
- 拥塞避免:cwnd == ssthresh, 每次cwnd和ssthresh都加1;
- 快重传和快恢复:如果不执行快重传和快恢复, 当发生超时,则cwnd = 1,ssthresh减半,从慢开始启动。 如果执行快重传和快恢复,则超时会收到三个重复确认,这时候ssthresh = ssthresh/2, cwnd = ssthresh,从拥塞避免开始。
-
ARQ协议(自动重传请求协议):基本原理是发完分组后停止发送,等待对方确认后再发送下一组。包括停止等待ARQ和连续ARQ协议:
- 停止等待ARQ:发送一个分组后停止发送,等待对方确认,如果超时则重新发送。在发送过程中,发送方和接收方会丢弃重复的确认和分组。简单,但是信道利用率低
- 连续ARQ协议发送方维持一个发送窗口,可以将发送窗口内的分组全部发送出去,不需要等待确认,接收方累计确认,按照顺序为最后一个分组发送确认响应。信道利用率高,但是有回退N现象,比如发送5个分组,3丢失,4,5正常,则需要重新发送3即之后的分组。
-
超时重传:TCP发送一个段后,启动一个计时器,如果不能及时收到确认消息则重发这个报文段
HTTP协议
HTTP结构
请求报文
- 请求行:包括请求方法、URL、协议/版本
- 请求头:一些信息
- 请求体:传输的数据内容
get请求一般不带实体主体,post请求一般带实体主体。
响应报文
- 响应行:协议/版本、响应状态码
- 响应头:一些信息
- 响应体:响应状态码和数据
HTTP的请求方式
Q:GET和POST的区别?
get请求参数以?分隔拼接到URL后面,post请求参数在Body内部。get参数长度显示2048个字符,post一般没有该限制。get请求不安全,post请求比较安全。
安全性表示不应该引起server端的任何状态变化。幂等性表示同一个请求方法执行多次和执行一次的效果完全相同。可缓存性表示请求是否可以被缓存。
HTTP状态码
| 2XX成功 | 3XX 重定向 | 4XX客户端错误 | 5XX服务端错误 |
|---|---|---|---|
| 200成功 | 400错误请求 | 500服务器错误 | |
| 201创建 | 301永久重定位 | 401未授权 | |
| 204无主体 | 302 临时重定向 | 502网关错误 | |
| 206范围请求 | 403禁止访问 | ||
| 304资源未修改 | 404未找到 | 504网关超时 | |
| 405请求方法不对 |
HTTP连接建立流程
HTTP的特点
- 无连接
HTTP持久连接方案可解决该问题
- 无状态
Cookie/Session
HTTP的持久连接
客户端向服务端双方建立连接之后,即使clinent与server完成一次读写,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。长连接可以省区较多的TCP建立和关闭的操作,节约时间。对于频繁请求资源的客户来说,非常使用长连接。HTTP1.1之后默认使用长连接。
Q:开启持久连接需要设置的头部字段
Connection: keep-alive需要开启持久连接time: 20持续时间max: 10持久连接最多可发起的网络请求次数
Q:怎样判断一个请求是否结束?
Content-length: 1024根据所接受数据是否达到Content-length来判断。chunkedpost请求会有多次返回,最后一次返回会有一个空的chunked。
HTTP的缓存机制
HTTP 缓存机制就是,配置服务器响应头来告诉浏览器是否应该缓存资源、是否强制校验缓存、缓存多长时间;浏览器非首次请求根据响应头是否应该取缓存、缓存过期发送请求头验证缓存是否可用还是重新获取资源的过程。下面我们就来结合简单的 node 服务器代码(文末)来介绍其中原理。
HTTP各版本特性
-
HTTP/0.9
-
无状态型(每个HTTP请求都要经历一次DNS解析,三次握手、传输和四次挥手)
-
不支持请求头(只支持纯文本内容)
-
只有GET请求
-
-
HTTP/1.0
-
持久连接 (一次TCP连接,可服务多个HTTP请求)
-
支持请求/响应头:
-
增加POST和HEADER请求
-
-
HTTP/1.1
-
默认持久连接,管道机制(一个TCP连接,允许多个请求同时发送,增加了并发性)
-
支持分块传输,断点续传,缓存处理
-
增加PURT、PATCH、OPTIONS、DELETE请求
-
-
HTTP/2.0
- 多路复用((二进制分帧)一个连接可以承载任意数量到双向数据流。每个数据流消息由一个或多个帧组成,帧可以乱序发送,然后再根据每个帧首部到流标识符重新组装)即连接共享,一个request请求对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
- 服务端推送 (等主动推送数据到客户端,类似长连接效果(长连接,客户端轮询))
- 头部压缩、随时复位、优先权等
Q:打开输入网页url到显示的过程是什么?
- DNS解析:查找域名对应的IP地址(浏览器缓存、路由器缓存、DNS缓存);
- TCP三次握手建立连接;
- 发送HTTP请求:附带请求参数和cookies(辨别用户身份,存储在用户本地的数据);
- 服务器处理请求返回HTTP响应;
- 浏览器渲染HTML页面;
- TCP四次挥手释放连接;
HTTPS与网络安全
HTTP和HTTPS的区别?
HTTPS就是在HTTP的基础之上,在应用层和传输层之间增加了SSL/TLS,为我们实现网络安全机制。HTTPS是安全的HTTP。HTTP默认80端口,HTTPS默认443端口;
SSL 协议可分为两层:
- SSL 记录协议(SSL Record Protocol),它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
- SSL 握手协议(SSL Handshake Protocol),它建立在 SSL 记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。在整个 SSL 握手中,都有一个唯一的随机数来标记 SSL 握手,这样可以防重放攻击。
- 数据保密性:保证数据内容在传输的过程中不会被第三方查看。就像快递员传递包裹一样,都进行了封装,别人无法获知里面装了什么 。
- 数据完整性:及时发现被第三方篡改的传输内容。就像快递员虽然不知道包裹里装了什么东西,但他有可能中途掉包,数据完整性就是指如果被掉包,我们能轻松发现并拒收 。
- 身份校验安全性:保证数据到达用户期望的目的地。就像我们邮寄包裹时,虽然是一个封装好的未掉包的包裹,但必须确定这个包裹不会送错地方,通过身份校验来确保送对了地方 。
HTTPS的建立流程?
- 客户端向服务器发送一段报文,报文内容包括
三部分,客户端支持的TLS协议版本,客户端支持的加密算法,一段随机数C。 - 服务器返回客户端一段握手的报文消息,内容也包括
三部分,服务器从客户端上报的多种加密算法中选择的加密算法,一段随机数S,服务器证书。 - 客户端对服务器返回的
证书进行验证,判断服务器是否是合法的服务器,即对服务器公钥进行验证。 - 客户端生成
预主密钥(46字节随机数), - 客户端通过
预主密钥、一段随机数C、一段随机数S,组装会话密钥。 - 客户端通过服务器的
公钥对预主密钥进行加密传输。 - 服务器通过
私钥解密得到预主密钥。 - 服务器通过
预主密钥、一段随机数C、一段随机数S,组装会话密钥。 - 客户端和服务器相互发送
加密的握手消息,验证握手是否完成。
会话秘钥
HTTPS的加密手段
- 连接建立过程使用
非对称加密,非对称加密很耗时。 - 后续通信过程使用
对称加密。
非对称加密
对称加密
- 对称加密秘钥如果遗失,可能会造成
中间人攻击。
Q:Charles抓包原理是怎样的?
- 是利用HTTP
中间人攻击漏洞来实现的。 - 中间人可以
篡改发送和接收的数据。
关于HTTPS的中间人攻击
过程原理:
- 本地请求被劫持(如DNS劫持等),所有请求均发送到中间人的服务器
- 中间人服务器返回中间人自己的证书
- 客户端创建随机数,通过中间人证书的公钥对随机数加密后传送给中间人,然后凭随机数构造对称加密对传输内容进行加密传输
- 中间人因为拥有客户端的随机数,可以通过对称加密算法进行内容解密
- 中间人以客户端的请求内容再向正规网站发起请求
- 因为中间人与服务器的通信过程是合法的,正规网站通过建立的安全通道返回加密后的数据
- 中间人凭借与正规网站建立的对称加密算法对内容进行解密
- 中间人通过与客户端建立的对称加密算法对正规内容返回的数据进行加密传输
- 客户端通过与中间人建立的对称加密算法对返回结果数据进行解密
- 由于缺少对证书的验证,所以客户端虽然发起的是 HTTPS 请求,但客户端完全不知道自己的网络已被拦截,传输内容被中间人全部窃取。
Q:对于HTTPS API接口,如何防止抓包呢? 既然问题出在证书信任问题上,那么解决方法就是在我们的APP中预置证书。在TLS/SSL握手时,用预置在本地的证书中的公钥校验服务器的数字签名,只有签名通过才能成功握手。由于数字签名是使用私钥生成的,而私钥只掌握在我们手上,中间人无法伪造一个有效的签名,因此攻击失败,无法抓包。同时,为了防止预置证书被替换,在证书存储上,可以将证书进行加密后进行「嵌入存储」,如嵌入在图片中或一段语音中。
网络参数签名
为了防止网络请求被篡改,一般会对请求参数进行hash,一般会有一个sign字段表示签名。
假定客户端请求参数dic如下:
{
"name":"akon",
"city":"shenzhen",
}
那么如何生成sign字段呢? 一般通用的做法是把字典按照key的字母升序排序然后拼接起来,然后再进行sha256,再md5。
- 把字典按照key的字母排序拼接生成字符串str = "city=shenzhen&name=akon"。
- 对str先进行sha256然后再进行md5生成sign。 值得注意的是,为了增加破解的难度,我们可以在生成的str前面、后面加入一段我们App特有的字符串,然后对str hash可以采用base64、sha256,md5混合来做。
网络参数加密方式
为了效率,我们一般会采用对称加密加密数据,DES,3DES,AES这些方式都可以。既然要用对称加密,那就涉及到对称加密的密钥怎么生成,有如下方式:
- 最简单的方式,代码写死密钥。密钥可以用base64或者抑或算法进行简单的加密,用的时候再解密,这种方式比裸写密钥更安全。
- 后台下发密钥。后台可以在登录的时候下发这个密钥,客户端保存这个密钥后续用来做加密。由于客户端要保存这个密钥,所以还是存在泄露的风险。
- 仿照https证书校验过程,客户端生成对称加密的密钥clientKey,对参数进行加密,然后用非对称加密对clientKey进行加密生成cryptKey传给后台;后台获取到cryptKey用密钥解析出clientKey,然后再用clientKey解密出请求参数。这种方式最安全,推荐使用。
证书
关于CA证书预制和申请
- 采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问。
- 客户端内置CA的根证书(Root Certificate)(浏览器、操作系统里), 里面包含
CA公钥。客户端(浏览器)的"证书管理器",有"受信任的根证书颁发机构"列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。(这边写的客户端内置CA根证书待考究) - 服务器去CA申请一个证书,CA用私钥对服务器公钥等信息进行加密生成了证书,然后发送给服务器。
- 为了确保根证书的绝对安全性,所以有了**证书链**,所以CA不会直接颁布证书,而是通过intermediates certificates给网站颁发证书
- 所谓证书链的验证,是想通过证书链追溯到可信赖的CA的根(ROOT)。换句话说,要验证签发用户实体证书的CA是否是权威可信的CA,如CFCA。证书链验证的要求是,路径中每个证书从最终实体到根证书都是有效的,并且每个证书都要正确地对应发行该证书的权威可信任性CA。
客户端验证证书,CA证书机制的形象表述
-
客户端 sayHello
-
服务器返回证书
-
客户端检验证书的合法性,合法性检验包括:
证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的 "发行者的数字签名",服务器证书上的域名是否和服务器的实际域名相匹配
- 验证证书内容有效性(过期时间, 域名是否相同等)
- 验证证书的有效性 (是否被串改), 通过查找"受信任的根证书颁发机构"列表,若找到对应证书的 公钥,就可以解密证书得到服务器公钥,再用服务器公钥解密数字签名得到摘要,然后再对信件本身使用哈希函数得到摘要,看两个摘要是否匹配,匹配的话数字签名通过,就可以使用服务器证书里面提供的公钥进行下一步通信。
iOS app签名机制
数字签名
数字签名的过程如下:
- 首先算出原始数据的摘要。这里的算法要保证:如果原始数据有任何变化,则摘要也会发生变化;对同一份原始数据,使用相同的算法,计算出的摘要是相同的。这一步使用的算法通常是MD5消息摘要算法。
- 生成一对公钥和私钥,使用非对称加密方式,用私钥对上一步生成的摘要进行加密,加密的结果就是数字签名。
- 在返回数据时,将原始数据和数字签名一起返回给请求数据方。
数字签名进行验证,过程如下:
- 首先用含有的公钥对数字签名进行解密,如果能够解密成功,说明返回的数据是经过数据发送方认证的(否则数据发送方不会对该数据加密)。
- 对原始的数据使用MD5算法,生成原始数据的摘要。
- 对比第一步和第二步生成的摘要,如果生成的摘要相等,说明原始数据没有被篡改过。
通过AppStore下载的app签名机制
了解了数字签名之后,来看下苹果是如何通过AppStore确保app合法的。 我们都知道,iPhone只有一家生产商,iOS系统只有一个开发者,那就是苹果公司。因此苹果公司可以在所有的iOS系统中做一些统一的事情。实际上,苹果公司生成了一对私钥和公钥,每一个iOS 系统上都内置有公钥,而私钥保存在苹果后台上。开发者再将app上传到苹果服务器之后,苹果公司使用私钥对app进行数字签名。用户从AppStore 下载的app,既包含app包,也包含数字签名。下载到本地后,iOS 系统使用公钥验证签名,就可以确定该app 是经过苹果公司认证的,且包没有被篡改过。整个流程如下: 
双层签名机制
双层签名的流程如下:
- 在本地Mac 生成一对公钥、私钥
- 苹果生成一对公钥、私钥。其中私钥在苹果后台管理,每台iOS设备中都有公钥。
- 将本地Mac生成的公钥(CertificateSigningRequest)上传至开发者后台,在这个过程中,苹果会使用私钥对该公钥进行签名,最后生成一个证书文件。该证书文件中包含公钥L的原始数据,以及签名信息。开发者需要将该证书下载到本地的Mac。
- 在开发阶段,将app安装到手机上时,使用本地Mac的私钥(p12文件)对app进行签名,最终打包到手机上的有 App原数据,使用本地私钥对app加密后的签名文件,以及上一步下载的证书文件。
- iOS 设备使用公钥A验证证书中的签名,如果验证通过,说明该公钥是经过苹果认证的(也就是证实了开发者身份)。
- 之后使用证书中的公钥L 验证App 签名,如果验证通过,说明该app 的安装是合法的。
DNS解析
DNS解析
域名到IP地址的映射,DNS解析请求采用UDP数据报,且明文。
DNS的解析过程
主机向本地域名服务器的查询一般都是采用递归查询:如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其它根域名服务器继续发出查询请求报文(即替主机继续查询),而不是让主机自己进行下一步查询。因此,递归查询返回的查询结果或者是所要查询的IP地址,或者是报错,表示无法查询到所需的IP地址。
本地域名服务器向根域名服务器的查询的迭代查询:当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:“你下一步应当向哪一个域名服务器进行查询”。然后让本地服务器进行后续的查询。根域名服务器通常是把自己知道的顶级域名服务器的IP地址告诉本地域名服务器,让本地域名服务器再向顶级域名服务器查询。顶级域名服务器在收到本地域名服务器的查询请求后,要么给出所要查询的IP地址,要么告诉本地服务器下一步应当向哪一个权限域名服务器进行查询。最后,知道了所要解析的IP地址或报错,然后把这个结果返回给发起查询的主机。
这两种查询的差别:
递归:客户端只发一次请求,要求对方给出最终结果,返回的结果只有两种:查询成功或查询失败
迭代:客户端发出一次请求,对方如果没有授权回答,它就会返回一个能解答这个查询的其它名称服务器列表,客户端会再向返回的列表中发出请求,直到找到最终负责所查域名的名称服务器,从它得到最终结果,返回的是最佳的查询点或者主机地址
DNS 缓存
为了提高DNS查询效率,域名服务器中广泛使用了DNS高速缓存,存放最近查询过的域名以及从何处获得域名映射信息的记录。由于名字到地址的绑定并不经常改变,为保持告诉缓存中的内容正确,域名服务器应为每项内容设置计时器TTL。增加此时间值可减少网络开销,而减少此时间值可提高域名解析的正确性。
一条域名的DNS记录会在本地有两种缓存:浏览器缓存和操作系统OS缓存。在浏览器中访问的时候,会优先访问浏览器缓存,如果未命中则访问OS缓存,最后再访问DNS服务器(一般是ISP提供),然后DNS服务器会递归式的查找域名记录,然后返回。DNS记录会有一个ttl值(time to live),单位是秒,意思是这个记录最大有效期是多少。
OS缓存会参考ttl值,但是不完全等于ttl值,
浏览器DNS缓存的时间跟ttl值无关,每种浏览器都使用一个固定值。
DNS解析常见的问题
- DNS劫持问题
- DNS解析转发问题
- 可能造成跨网访问,效率降低。
Q:DNS劫持与HTTP的关系是怎样的?
没有关系DNS解析发生在HTTP建立连接之前DNS解析请求使用UDP数据报,端口号53
怎么解决DNS劫持?
-
httpDNS
-
使用
HTTP协议向DNS服务器的80端口进行请求
-
-
长连接
Session/Cookie
HTTP协议无状态特点的补偿
Cookie
Cookie主要用来记录用户状态,区分用户;状态保存在客户端。
客户端发送的cookie在http请求报文的Cookie首部字段中。服务器端设置http响应报文的Set-Cookie首部字段。
Q:怎样修改Cookie?
- 新
cookie覆盖旧cookie。 - 覆盖规则:
name、path、domain等需要与原cookie一致。
Q:怎样删除Cookie?
- 新
cookie覆盖旧cookie。 - 覆盖规则:
name、path、domain等需要与原cookie一致。 - 设置
cookie的expires=过去的一个时间点,或者maxAge=0。
Q:怎样保证Cookie的安全?
- 对
Cookie进行加密处理。 - 只在
https上携带Cookie。 - 设置
Cookie为httpOnly,防止跨站脚本攻击。
Session
Session也是用来记录用户状态,区分用户的;状态存放在服务器端。Seesion需要依赖于Cookie机制实现。