- OSI七层协议及TCP/IP四层协议
- 通信交互方式
- MAC地址和IP地址
- ARP协议的作用
- ping发生了什么
- traceroute发生了什么
- TCP/UDP的区别和应用场景
- 拥塞控制和流量控制的区别
- TCP滑动窗口实现流量控制
- TCP超时重传
- TCP拥塞机制
- TCP三次握手及三次缘由
- TCP四次挥手及四次缘由
- TIME-WAIT状态及2MSL时间
- 域名系统DNS
- 统一资源定位符URL
- 描述一下HTTP协议
- HTTP2.0
- HTTP持久连接与管线化
- HTTP协议请求报文具体信息
- GET和POST的区别
- HTTP协议响应报文具体信息
- HTTP状态码
- 浏览器键入URL后的访问流程
- IP/TCP/UDP分片
- 对称密钥和公钥密码体制
- 数字签名和数字证书
- HTTP和HTTPS的区别
- 运输层安全协议及SSL工作过程
- HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?
- cookie和session
- 浏览器关闭后,session就销毁了吗
互联网是由许多小型网络构成的,每个网络上都有许多主机,这样便构成了一个有层次的结构。IP地址在设计时就考虑到地址分配的层次特点,将每个IP地址都分割成网络号和主机号两部分,以便于IP地址的寻址操作。
IP地址的网络号和主机号各是多少位呢?如果不指定,就不知道哪些位是网络号、哪些是主机号,这就需要通过子网掩码来实现。
什么是子网掩码 子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。子网掩码的设定必须遵循一定的规则。与IP地址相同,子网掩码的长度也是32位,左边是网络位,用二进制数字“1”表示;右边是主机位,用二进制数字“0”表示。
网关(Gateway)就是一个网络连接到另一个网络的“关口”。 按照不同的分类标准,网关也有很多种。TCP/IP协议里的网关是最常用的,在这里我们所讲的“网关”均指TCP/ IP协议下的网关。
七层协议:物、数、网、传、会、表、应
四层协议:网络接口层(物理层,数据链路层),网络层(网络层),传输层(传输层),应用层(会话层,表示层,应用层)
不同的协议层对数据包有不同的称谓,在传输层叫段,在网络层叫数据报,在链路层叫帧。
说到MAC地址表,就不得不说一下交换机的工作原理了,因为交换机是根据MAC地址表转发数据帧的。在交换机中有一张记录着局域网主机MAC地址与交换机接口的对应关系的表,交换机就是根据这张表负责将数据帧传输到指定的主机上的。
交换机在接收到数据帧以后,首先、会记录数据帧中的源MAC地址和对应的接口到MAC表中,接着,会检查自己的MAC表中是否有数据帧中目标MAC地址的信息,如果有则会根据MAC表中记录的对应接口将数据帧发送出去(也就是单播),如果没有,则会将该数据帧从非接收接口发送出去(也就是广播)。
源MAC地址为自己
,目标MAC地址为主机B
(如何得到主机B的MAC地址下面再讲)的数据帧发送给交换机;记录
到MAC地址表中;检查自己的MAC地址表
中是否有目标MAC地址的信息,如果有,则从MAC地址表中记录的接口发送数据帧;如果没有,则将数据帧从非接收的所有其他接口发送出去(广播);源MAC地址为自己
,目标MAC地址为主机C
的数据帧发送给交换机1;==注意:==交换机具有动态学习源MAC地址的功能,并且交换机的一个接口可以对应多个MAC地址,但是一个MAC地址只能对应一个接口。交换机动态学习的MAC地址默认只有300S的有效期,如果300S内记录的MAC地址没有通信,则会删除此记录。
上面我们讲解了交换机的工作原理,知道交换机是通过MAC地址通信的,但是我们是如何获得目标主机的MAC地址呢?这时我们就需要使用ARP协议了,在每台主机中都有一张ARP表,它记录着主机的IP地址和MAC地址的对应关系。
windows/linux下可以通过命令行中输入"arp -a"
查看本机的ARP缓存表。
路由器负责不同网络之间的通信,它是当今网络中的重要设备,可以说没有路由器就没有当今的互联网。在路由器中也有一张表,这张表叫路由表,记录着到不同网段的信息。
在cmd
中,输入route print -4
查看ipv4路由表
在linux
主机上,使用route -n
查看当前路由表
总结:路由表负责记录一个网络到另一个网络的路径,因此路由器是根据路由表工作的。
假如主机A向主机B通信,主机A需要得到主机B的MAC地址,首先主机A会利用子网掩码的与操作来判断主机B与自己是否在同一网段,如果在同一网段,就会使用ARP协议到ARP缓存表中去查询主机B的MAC地址(流程就是上述ARP缓存表的流程);如果不在同一网段,主机A会查询路由表看有没有能到达B主机所在网络的具体路由,如果找不到,就找到默认网关的IP地址,将默认网关作为自己的下一跳,但是还需要得到默认网关的MAC地址(即F0/0)接口的MAC地址;这时主机A会通过ARP请求来找到网关的MAC地址,然后将数据帧的目的MAC地址设置为路由器的F0/0接口,目的IP地址仍然是主机B的IP地址,并将数据帧转发到网关;到了路由器之后,路由器如何知道下一步要往哪发送呢?当路由器从F0/0接口接收到数据帧后,就会按照上述路由表流程来查询接下来的转发路径。(要注意,如果在路由器的路由表里找到多个匹配的路由项,路由查找进程会选择其中掩码最长
的路由项进行转发,掩码越长表明代表的网络范围越小,匹配的程度就越精确。这就是所谓的最长匹配原则。如果找不到路由项,则丢弃该IP报文。但是如果在路由表中有缺省路由存在,则路由器将按照缺省路由来转发IP报文。缺省路由又称为默认路由,其目的地址和子网掩码均为0.0.0.0。)
网络层使用的是IP地址,数据链路层使用的是硬件地址。
ARP协议的用途是为了从网络层使用的IP地址,解析出数据链路层使用的硬件地址。
判断是否为ARP病毒攻击
ping主要是为了测试两台主机之间的连通性,通过应用层直接使用网络层ICMP,没有通过运输层TCP和UDP,是通过发送ICMP报文回显请求实现。
- A主机构建一个ICMP格式的数据包,通过ICMP协议把该数据包和B主机的IP地址一起交给IP协议;
- IP层构建一个数据包(A主机的IP地址+控制信息+B主机的IP地址),并获得B主机的MAC地址,以便构建一个数据帧(IP协议会根据B主机的IP地址和自己的子网掩码判断是不是属于同一层网络,如果是属于同一层网络的话,就能通过ARP协议获得B主机的MAC地址,如果不在同一个网络,那就会先将数据包发送给网关,再由网关来决定发送到哪)
- 主机B接受到主机A的发过来的数据帧以后,先检查该帧中包含的B的IP地址,并和本地的物理地址进行比对,如果符合的话,就接受,否则,就抛弃。同样,需要将该数据帧交由自己的IP层协议,IP层检查以后,再交由ICMP协议,构建一个ICMP的应答包,发送给主机A。
ping不通的原因有很多:
- 对方关机
- 目标ip不存在
- 位于不同网段,且路由器在路由表中无法找到
- 防火墙设置导致过滤了ping发出的ICMP数据包
- 网线故障
traceroute用来跟踪一个分组从源点到终点的路径,及到达其中每一个路由器的往返时间
32位序号seq
:一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号。假设主机A和主机B进行通信,A发送给B的第一个TCP报文段中,序号被系统初始化位某个随机值ISN。那么在该传输方向上,后续的TCP报文段中序号值将被系统设置成ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。32位确认号ack
:用作对另一方发来的TCP报文段的响应,其值是收到的TCP报文段的序号值+1。4位首部长度
:标识该TCP头部有多少个32bit字(4字节),因为4位最多表示15,所以说整个首部最多有4×15 = 60个字节,除去固定的20个字节,还有40个字节,也就是说可变长度部分最多占40个字节。6位保留位
:为将来定义新的用途保留,现在一般置0URG
:标记位表示紧急指针是否有效。ACK
:表示确认号ack是否有效,为0确认号就无效,发送通信请求时为0,允许通信后就变为1。PSH
:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。RST
:表示要求对方重新建立连接。若为1,表示TCP会话出现严重错误,需要释放连接,需重新建立连接才可正常通信,比如点开一个网页,还在加载时,点击×就会中断连接,后面的数据报RST就为1,点击刷新就相当于重新建立连。SYN
:表示请求建立连接,发起会话的话SYN就为1,当会话建立后SYN就变为0了。FIN
:表示通知对端,本端要关闭连接了,在数据通信结束后,要释放连接,后面的数据报FIN位就为116位窗口大小
:发送方和接收方都需要发送窗口和接收窗口,双方在建立会话时,会确定各自的窗口大小,以此来协商发送数据包的大小16位检验和
:由发送端填充,接收端对TCP报文执行CRC算法以检验TCP报文段在传输过程中是否损坏。16位紧急指针
:是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。16位UDP长度
:UDP用户数据报的长度,即首部+数据。16位UDP校验和
:检测UDP用户数据报长度在传输中是否有错,有错就丢弃。TCP,全称:传输控制协议,面向连接的安全的流式传输协议
UDP,全称:用户数据报协议,面向无连接的不安全的报式传输协议
连接
服务对象
可靠性
拥塞控制,流量控制
报文长度
首部开销
流量控制是让发送方的发送速率不要太快,要让接收方来得及接收,实现对发送方的流量控制.
滑动窗口出现的原因:在确认应答策略中,对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段,这样做有一个比较大的缺点,就是性能比较差,尤其是数据往返的时间长的时候
滑动窗口以字节为单位,而不是报文
(1)接收端将自己可以接收的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK来通知发送端
(2)窗口大小字段越大,说明网络的吞吐率越高
(3)窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,即就是说不需要接收端的应答,可以一次连续的发送数据
(4)操作系统内核为了维护滑动窗口,需要开辟发送缓冲区,来记录当前还有那些数据没有应答,只有确认应答过的数据,才能从缓冲区删掉
(5)接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端,发送端收到这个值后,就会减慢自己的发送速度
(6)如果接收端发现自己的缓冲区满了,就会将窗口的大小设置为0,此时发送端将不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端
ps:发送缓冲区如果太大,就会有空间开销
慢启动,拥塞避免,快恢复,快重传
发送方维持拥塞窗口cwnd
发送方控制拥塞窗口的原则是:
只要网络没有出现拥塞,拥塞窗口就再增大一些(2倍增长),以便把更多的分组发送出去。
只要网络出现拥塞,拥塞窗口就减小一些,以减少注入网络中的分组数。
流程:初始时设置慢开始门限ssthresh为16,第1次传输窗口大小为1,然后呈指数增长,当增长到16(即慢开始门限ssthresh)后,此时就需要慢增长了,每次窗口大小只增长1直到网络出现拥塞。假如当窗口增长到24时网络出现了拥塞,这时就要设置新的慢开始门限ssthresh了,新值应该是网络开始出现拥塞时窗口大小的1/2,即12。然后,窗口大小重新从1开始增长,增长到慢开始门限ssthresh后,再慢慢增长。
强调:“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞阶段把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认。这样做可以让发送方及早知道有报文段没有到达接收方
当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限ssthresh减半,但拥塞窗口cwnd现在不设置为1,而是设置慢开始门限ssthresh减半后的值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
三次握手其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。
进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
四次报文中服务器端发送给客户端的请求关闭连接报文FIN和ACK也是合并的,相对于三次来说,只是前面多了一次ACK的确认。
保证客户端发送的最后一个ACK报文段能够到达服务端
。若B收不到A的ACK报文,则B会超时重传FIN+ACK,A会在2MSL时间内收到重传报文段,然后发送ACK,重新启动2MSL计时器防止“已失效的连接请求报文段”出现在本连接中
。2MSL后,本次连接的所有报文都会消失,使下一个新的连接中不会出现这种旧的连接请求报文段。TIME_WAIT有助于可靠地实现TCP全双工连接的终止
。在高并发短连接的TCP服务器
上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态
。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
客户端异常断开,服务器没有捕捉到异常,从而没有使用close()关闭socket,(调用close后就不再是CLOSE_WAIT状态)。总的来说,就是服务器没有调用或没有及时调用close()。
可能的原因:
程序Bug,接收到FIN信号后没有及时关闭socket,这可能是Netty的Bug,也可能是业务层Bug;
关闭socket不及时:例如I/O线程被意外阻塞,或者I/O线程执行的用户自定义Task比例过高,导致I/O操作处理不及时,链路不能被及时释放。
用于将域名转换为IP地址。
DNS解析过程有两种,分别是递归查询和迭代查询。
DNS域名解析过程:
本地域名服务器
(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。根域名服务器
请求解析。顶级域名服务器
(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址。Name Server
的地址,这个Name Server就是网站注册的域名服务器。ping
域名,如果没有IP表示域名错误或者域名未作解析,如果超时表示服务器有问题nslookup
命令,如果出现超时表明DNS出现问题统一资源定位符URL,用来表示从互联网上得到的资源位置。
一般由四个部分组成
使用HTTP的URL
优缺
点:
HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。
HTTP 请求/响应的步骤
- 客户端连接到Web服务器
一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.oakcms.cn。- 发送HTTP请求
通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。- 服务器接受请求并返回HTTP响应
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。- 释放连接TCP连接
若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;- 客户端浏览器解析HTML内容
客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
版本号 | 产生时间 | 内容 | 发展现状 |
---|---|---|---|
HTTP/0.9 | 1991年 | 不涉及数据包传输,规定客户端与服务器之间的通信格式,只能GET请求 | 没有作为正式的标准 |
HTTP/1.0 | 1996年 | 传输内容格式不限制,增加PUT、PATCH、HEAD、OPTIONS、DELETE命令 | 正式作为标准 |
HTTP/1.1 | 1997年 | 持久连接(长连接)、节约带宽、HOST域、管道机制、分块传输编码 | 2015年前使用最广泛 |
HTTP/2 | 2015年 | 多路复用、服务器推送、头信息压缩、二进制协议等 | 逐渐覆盖市场 |
HTTP协议首先要和服务器建立TCP连接,这需要三次握手。
请求一个万维网文档的时间
HTTP1.0非持久连接的缺点
HTTP1.1持久连接
持久连接的两种工作方式
HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据四个部分组成
GET
GET /562f25980001b1b106000338.jpg HTTP/1.1
Host:img.mukewang.com
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept:image/webp,image/*,*/*;q=0.8
Referer:http://www.imooc.com/
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
空行
请求数据为空
POST
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive
空行
name=Professional%20Ajax&publisher=Wiley
- 请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.
GET说明请求类型为GET,/562f25980001b1b106000338.jpg(URL)为要访问的资源,该行的最后一部分说明使用的是HTTP1.1版本。- 请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息
* HOST,给出请求资源所在服务器的域名.
* User-Agent,HTTP客户端程序的信息,该信息由你发出请求使用的浏览器来定义,并且在每个请求中自动发送等
* Accept,说明用户代理可处理的媒体类型
* Accept-Encoding,说明用户代理支持的内容编码
* Accept-Language,说明用户代理能够处理的自然语言集
* Content-Type,说明实现主体的媒体类型
* Content-Length,说明实现主体的大小
* Connection,连接管理,可以是Keep-Alive或close- 空行,请求头部后面的空行是必须的即使第四部分的请求数据为空,也必须有空行。
- 请求数据也叫主体,可以添加任意的其他数据。
PUT是幂等的方法,POST不是
GET /books/?sex=man&name=Professional HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive
空行
请求数据为空
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
- 状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。
第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为OK- 消息报头,用来说明客户端要使用的一些附加信息
第二行和第三行为消息报头,Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8- 空行,消息报头后面的空行是必须的
- 响应正文,服务器返回给客户端的文本信息。空行后面的html部分为响应正文
数据发送时,将数据从应用层->传输层->网络层->数据链路层,其中传输层是TCP和UDP,网络层是IP协议。
MTU以太网帧的长度为1500字节,所能接收的传输层数据段最大为 1480 个字节(以太网帧中的数据包括 IP 协议的报头信息,IP 协议的报头信息为 20 字节)
在计算 MSS (网络传输数据最大值)的时候,用 MTU 减去网络层报头长度以及传输层报头长度即可。
UDP
中间人攻击
。所以我们才需要对信息进行加密。最直接的加密方式就是对称加密
。如果通信双方都各自持有同一个密钥,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)。
然而最大的问题就是**这个密钥怎么让传输的双方知晓,同时不被别人知道**。如果由服务器生成一个密钥并传输给浏览器,那这个传输过程中密钥被别人劫持弄到手了怎么办?之后他就能用密钥解开双方传输的任何内容了,所以这么做当然不行。
换种思路?试想一下,如果浏览器内部就预存了网站A的密钥,且可以确保除了浏览器和网站A,不会有任何外人知道该密钥,那理论上用对称加密是可以的,这样浏览器只要预存好世界上所有HTTPS网站的密钥就行啦!这么做显然不现实。
怎么办?所以我们就需要神奇的非对称加密
我们已经理解通过一组公钥私钥,已经可以保证单个方向传输的安全性,那用两组公钥私钥,是不是就能保证双向传输都安全了?请看下面的过程:
的确可以!抛开这里面仍有的漏洞不谈(下文会讲),HTTPS的加密却没使用这种方案,为什么?最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快很多,看来必须得用对称加密,那我们能不能运用非对称加密的特性解决前面提到的对称加密的问题?
既然非对称加密耗时,非对称加密+对称加密结合可以吗?而且得尽量减少非对称加密的次数。当然是可以的,而且非对称加密、解密各只需用一次即可。
请看一下这个过程:
完美!HTTPS基本就是采用了这种方案。完美?还是有漏洞的。
中间人的确无法得到浏览器生成的密钥B,这个密钥本身被公钥A加密了,只有服务器才有私钥A’解开拿到它呀!然而中间人却完全不需要拿到密钥A’就能干坏事了。请看:
这样在双方都不会发现异常的情况下,中间人得到了密钥X。根本原因是浏览器无法确认自己收到的公钥是不是网站自己的。那么下一步就是解决下面这个问题:
现实生活中,如果想证明某身份证号一定是小明的,怎么办?看身份证。这里政府机构起到了“公信”的作用,身份证是由它颁发的,它本身的权威可以对一个人的身份信息作出证明。互联网中能不能搞这么个公信机构呢?给网站颁发一个“身份证”?
网站在使用HTTPS前,需要向“CA机构”申请颁发一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”。然而这里又有一个显而易见的问题了,证书本身的传输过程中,如何防止被篡改?即如何证明证书本身的真实性?身份证有一些防伪技术,数字证书怎么防伪呢?解决这个问题我们就基本接近胜利了!
我们把证书内容生成一份“签名”,比对证书内容和签名是否一致就能察觉是否被篡改。这种技术就叫数字签名
:
数字签名的制作过程:
明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了。
那浏览器拿到服务器传来的数字证书后,如何验证它是不是真的?(有没有被篡改、掉包)
浏览器验证过程:
假设中间人篡改了证书的原文,由于他没有CA机构的私钥,所以无法得到此时加密后签名,无法相应地篡改签名。浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。
既然不可能篡改,那整个证书被掉包呢?
假设有另一个网站B也拿到了CA机构认证的证书,它想搞垮网站A,想劫持网站A的信息。于是它成为中间人拦截到了A传给浏览器的证书,然后替换成自己的证书,传给浏览器,之后浏览器就会错误地拿到B的证书里的公钥了,会导致上文提到的漏洞。
其实这并不会发生,因为证书里包含了网站A的信息,包括域名,浏览器把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。
我初学HTTPS的时候就有这个问题,似乎以上过程中hash有点多余,把hash过程去掉也能保证证书没有被篡改。
最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加密解密就会快很多。
操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥了。
实际上证书之间的认证也可以不止一层,可以A信任B,B信任C,以此类推,我们把它叫做
信任链
或数字证书链
,也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。
另外,不知你们是否遇到过网站访问不了、提示要安装证书的情况?这里安装的就是根证书。说明浏览器不认给这个网站颁发证书的机构,那么没有该机构的根证书,你就得手动下载安装(风险自己承担XD)。安装该机构的根证书后,你就有了它的公钥,就可以用它验证服务器发来的证书是否可信了。
使用公钥密码加密的一般流程:通过A的公钥对报文加密,发送给B,然后B拿A的私钥进行解密,得到报文.
注意:并不是每次传输报文的时候都要加数字签名,数字签名一般用于数字证书的验证,这样的话浏览器内置的CA拥有服务端的公钥和私钥。
数字签名
普通数字签名(能核实发送者,但无法保证报文完整性)
密码散列函数
报文摘要数字签名(核实发送者,保证报文完整性)
对报文本身加密可能是个耗时过程,比如这封Email足够大,那么私钥加密整个文件以及拿到文件后的解密无疑是巨大的开销
数字签名的作用
数字证书
明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了,由认证中心(CA)或者认证中心的下级认证中心颁发。通俗来说,A确认收到的公钥真的是B的公钥,而不是别人伪造的
- HTTP协议是以明文的方式在网络中传输数据,而HTTPS协议传输的数据则是经过TLS加密后的,HTTPS具有更高的安全性
- HTTPS可以保证报文完整性,另外可以核实发送者身份
- HTTPS协议需要服务端申请证书,浏览器端安装对应的根证书
- HTTPS在TCP三次握手阶段之后,还需要进行SSL的handshake,协商加密使用的对称加密密钥
- HTTP协议端口是80,HTTPS协议端口是443
传统的HTTP协议通信:传统的HTTP报文是直接将报文信息传输到TCP然后TCP再通过TCP套接字发送给目的主机上。
HTTPS协议通信:HTTPS是HTTP报文直接将报文信息传输给SSL套接字进行加密,SSL加密后将加密后的报文发送给TCP套接字,然后TCP套接字再将加密后的报文发送给目的主机,目的主机将通过TCP套接字获取加密后的报文给SSL套接字,SSL解密后交给对应进程。
显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?用session就行。
HTTP协议作为无状态协议,对于HTTP协议而言,无状态指每次request请求之前是相互独立的,当前请求并不会记录它的上一次请求信息,如何将上下文请求进行关联呢?客户端(不同的浏览器)记录用户的状态通过cookie,服务器端(不同的网站)记录用户的状态通过session。
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie,它是服务器端存放在本地机器中的数据,随每一个请求发送给服务器,由于Cookie在客户端,所以可以编辑伪造,不是十分安全。
Session是另一种记录客户状态的机制,它是在服务端保存的一个数据结构(主要存储的的SessionID和Session内容,同时也包含了很多自定义的内容如:用户基础信息、权限信息、用户机构信息、固定变量等),这个数据可以保存在集群、数据库、文件中,用于跟踪用户的状态。
客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
session是存放在服务器里的,所以session 里的东西不断增加会增加服务器的负担,我们会把一些重要的东西放在session里,不太重要的放在客户端cookie里
session失效
sessionID的传递方式
不同场景下的session
服务器为每个Cookie项生成签名。如果用户篡改Cookie,则与签名无法对应上。以此,来判断数据是否被篡改。
原理如下:
secret
secret(wall)=34Yult8i
username=wall|34Yult8i
。其中,内容和签名用|
隔开。Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌。当客户端第一次访问服务端,服务端会根据传过来的唯一标识userId,运用一些算法,并加上密钥,生成一个Token,然后通过BASE64编码一下之后将这个Token返回给客户端,客户端将Token保存起来(可以通过数据库或文件形式保存本地)。下次请求时,客户端只需要带上Token,服务器收到请求后,会用相同的算法和密钥去验证Token。
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
浏览器关闭和服务器session销毁没有任何关系,会话Cookie(非持久cookie)在关闭浏览器后就会消失,但是原来服务器的Session还在,只有等到了销毁的时间会自动销毁。
HTTPS 连接大致上可以划分为两个部分,第一个是建立连接时的非对称加密握手,第二个是握手后的对称加密报文传输。
由于目前流行的 AES(高级加密标准)、ChaCha20 (加密算法)性能都很好,还有硬件优化,报文传输的性能损耗可以说是非常地小,小到几乎可以忽略不计了。所以,通常所说的“HTTPS 连接慢”指的就是刚开始建立连接的那段时间。
在 TCP 建连之后,正式数据传输之前,HTTPS 比 HTTP 增加了一个 TLS 握手的步骤,这个步骤最长可以花费两个消息往返,也就是 2-RTT。而且在握手消息的网络耗时之外,还会有其他的一些“隐形”消耗,比如:
产生用于密钥交换的临时公私钥对(ECDHE);
验证证书时访问 CA 获取 CRL 或者 OCSP;
非对称加密解密处理“Pre-Master”。
在最差的情况下,也就是不做任何的优化措施,HTTPS 建立连接可能会比 HTTP 慢上几百毫秒甚至几秒,这其中既有网络耗时,也有计算耗时,就会让人产生“打开一个 HTTPS 网站好慢啊”的感觉。
不过刚才说的情况早就是“过去时”了,现在已经有了很多行之有效的 HTTPS 优化手段,运用得好可以把连接的额外耗时降低到几十毫秒甚至是“零”。
在计算机世界里的“优化”可以分成“硬件优化”和“软件优化”两种方式,先来看看有哪些硬件的手段。
首先,你可以选择更快的 CPU,最好还内建 AES 优化,这样即可以加速握手,也可以加速传输。
其次,你可以选择“SSL 加速卡”,加解密时调用它的 API,让专门的硬件来做非对称加解密,分担 CPU 的计算压力。
不过“SSL 加速卡”也有一些缺点,比如升级慢、支持算法有限,不能灵活定制解决方案等。
所以,就出现了第三种硬件加速方式:“SSL 加速服务器”,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算,性能自然要比单纯的“加速卡”要强大的多。
不过硬件优化方式中除了 CPU,其他的通常可不是靠简单花钱就能买到的,还要有一些开发适配工作,有一定的实施难度。比如,“加速服务器”中关键的一点是通信必须是“异步”的,不能阻塞应用服务器,否则加速就没有意义了。
所以,软件优化的方式相对来说更可行一些,性价比高,能够“少花钱,多办事”。
软件方面的优化还可以再分成两部分:一个是软件升级,一个是协议优化。
实施起来比较简单,就是把现在正在使用的软件尽量升级到最新版本,比如把 Linux 内核由 2.x 升级到 4.x,把 Nginx 由 1.6 升级到 1.16,把 OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1。
由于这些软件在更新版本的时候都会做性能优化、修复错误,只要运维能够主动配合,这种软件优化是最容易做的,也是最容易达成优化效果的。
从刚才的 TLS 握手图中你可以看到影响性能的一些环节,协议优化就要从这些方面着手,先来看看核心的密钥交换过程。
如果有可能,应当尽量采用 TLS1.3,它大幅度简化了握手的过程,完全握手只要 1-RTT,而且更加安全。
如果暂时不能升级到 1.3,只能用 1.2,那么握手时使用的密钥交换协议应当尽量选用椭圆曲线的 ECDHE 算法。它不仅运算速度快,安全性高,还支持“False Start”,能够把握手的消息往返由 2-RTT 减少到 1-RTT,达到与 TLS1.3 类似的效果。